企迹(qiji) 政企周报管理系统 — v0.1

后端: FastAPI + SQLAlchemy 2.0 (async) + Alembic + MinIO + Casdoor + 企微
前端: Vue 3 + Vite + TypeScript + Element Plus + Pinia

功能清单:
- 8 张数据表自动建表 / Casdoor OIDC 登录 / 企微静默登录
- 双布局: 移动端(填报) + PC端(汇总管理)
- 拜访记录 CRUD + MinIO 照片直传 + 缩略图预览 + 同访人草稿
- 今日纪要 (6 分类) / 工作计划 / 小微商机 / 要客拜访 CRUD
- 客户档案: 备注/收支费用/联系人/归属分配/批量转移
- 客户导入导出 + 模板下载 + 搜索/分页/筛选
- 仪表盘: 四卡统计 + 填报进度 (拜访+纪要双维度)
- 周报详情: 五 Tab + 按人/客户筛选 + 时间轴
- 用户管理 / 客户经理 PC 端工作台
- 企微: 催办/公告/定时提醒 / 时区修正
- Docker 部署配置

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-23 01:35:46 +08:00
parent 2a8225c31f
commit a1886074dd
97 changed files with 8830 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import { authApi } from '@/api/auth'
export const useAuthStore = defineStore('auth', () => {
const token = ref(localStorage.getItem('token') || '')
const userId = ref(localStorage.getItem('userId') || '')
const name = ref(localStorage.getItem('userName') || '')
const role = ref(localStorage.getItem('userRole') || '')
const isLoggedIn = computed(() => !!token.value)
const isManager = computed(() => role.value === 'manager')
const isDirector = computed(() => role.value === 'director')
const isLeader = computed(() => role.value === 'leader')
function saveLogin(data: { access_token: string; user_id: string; name: string; role: string }) {
token.value = data.access_token
userId.value = data.user_id
name.value = data.name
role.value = data.role
localStorage.setItem('token', data.access_token)
localStorage.setItem('userId', data.user_id)
localStorage.setItem('userName', data.name)
localStorage.setItem('userRole', data.role)
}
function logout() {
token.value = ''
userId.value = ''
name.value = ''
role.value = ''
localStorage.clear()
}
async function casdoorLogin(code: string, state: string) {
const res = await authApi.casdoorLogin(code, state)
saveLogin(res.data)
return res.data
}
async function wecomLogin(code: string) {
return await authApi.wecomLogin(code)
}
async function bindWecom(casdoorCode: string, wecomUserid: string) {
const res = await authApi.bindWecom(casdoorCode, wecomUserid)
saveLogin(res.data)
return res.data
}
return {
token, userId, name, role,
isLoggedIn, isManager, isDirector, isLeader,
saveLogin, logout, casdoorLogin, wecomLogin, bindWecom,
}
})