diff --git a/backend/src/api/crmPipeline.js b/backend/src/api/crmPipeline.js index 711775e..4aba774 100644 --- a/backend/src/api/crmPipeline.js +++ b/backend/src/api/crmPipeline.js @@ -73,6 +73,14 @@ export function changeBusinessStage(id, stage) { return request({ url: `/backend/crm/business/${id}/stage`, method: "post", data: { stage } }); } +/** + * 商机状态流转:1跟进中 / 3已废弃。 + * 「已转化项目(2)」不走本接口,须用 convertBusinessToProject 完成(会锁定商机)。 + */ +export function changeBusinessStatus(id, status) { + return request({ url: `/backend/crm/business/${id}/status`, method: "post", data: { status } }); +} + /* --------------------------------- 项目 --------------------------------- */ export function getProjectList(params) { diff --git a/backend/src/api/oaDailyReport.js b/backend/src/api/oaDailyReport.js new file mode 100644 index 0000000..4ea62ef --- /dev/null +++ b/backend/src/api/oaDailyReport.js @@ -0,0 +1,81 @@ +import request from '@/utils/request' + +// OA 工作日报 +// 响应拦截器只返回 {code, data, msg} 包装,调用方需自行取 res.data + +// 当前用户身份与可见范围:{ user_id, org_id, is_admin, can_view_team, window_start, window_end, backfill_days } +export function getDailyReportProfile() { + return request({ + url: '/backend/oa/dailyreport/profile', + method: 'get' + }) +} + +// 我的日报列表:params = { page, pageSize, start_date, end_date } +// data = { list, total, summary: { month_total, month_submitted, today_status, today_report_id, window_start, window_end } } +export function getMyDailyReports(params) { + return request({ + url: '/backend/oa/dailyreport/mine/list', + method: 'get', + params + }) +} + +// 保存日报:{ date, today_done, tomorrow_plan, issues, attachments, submit } +// submit=true 提交,false 存草稿;同一人同一天只会有一条记录 +export function saveDailyReport(data) { + return request({ + url: '/backend/oa/dailyreport/save', + method: 'post', + data + }) +} + +// 日报详情:{ report, comments, can_edit, can_delete, can_comment } +export function getDailyReportDetail(id) { + return request({ + url: `/backend/oa/dailyreport/detail/${id}`, + method: 'get' + }) +} + +export function deleteDailyReport(id) { + return request({ + url: `/backend/oa/dailyreport/delete/${id}`, + method: 'delete' + }) +} + +// 团队汇总:params = { date, org_id, keyword, page, pageSize } +// data = { date, list, total, stats: { total, submitted, missing, rate } } +export function getTeamDailyReports(params) { + return request({ + url: '/backend/oa/dailyreport/team/status', + method: 'get', + params + }) +} + +// 团队筛选部门:data = { list: [{ id, parent_id, name, member_count }] } +export function getTeamDailyReportOrgs() { + return request({ + url: '/backend/oa/dailyreport/team/orgs', + method: 'get' + }) +} + +// 评论 / 回复:{ report_id, content, reply_to_id } +export function addDailyReportComment(data) { + return request({ + url: '/backend/oa/dailyreport/comment', + method: 'post', + data + }) +} + +export function deleteDailyReportComment(id) { + return request({ + url: `/backend/oa/dailyreport/comment/${id}`, + method: 'delete' + }) +} diff --git a/backend/src/api/site.js b/backend/src/api/site.js new file mode 100644 index 0000000..5476726 --- /dev/null +++ b/backend/src/api/site.js @@ -0,0 +1,9 @@ +import request from '@/utils/request'; + +// 平台「小程序配置」中已启用的小程序(含二维码地址,公开接口无需登录) +export function getSiteMiniApps() { + return request({ + url: '/site/miniapp', + method: 'get', + }); +} diff --git a/backend/src/components/CommonAside.vue b/backend/src/components/CommonAside.vue index 9884d83..59db294 100644 --- a/backend/src/components/CommonAside.vue +++ b/backend/src/components/CommonAside.vue @@ -1,7 +1,10 @@ + + + @@ -172,6 +195,7 @@ import { ref, computed, onMounted, onUnmounted, watch } from "vue"; import { useRouter, useRoute } from "vue-router"; import { Document, Warning } from "@element-plus/icons-vue"; import { useAllDataStore, useMenuStore } from "@/stores"; +import { getSiteMiniApps } from "@/api/site"; const emit = defineEmits(["menu-click"]); @@ -195,6 +219,37 @@ const activeBgColor = ref("#3973FF"); const currentModuleId = ref(null); +// ---------- 底部小程序码 ---------- +// 来源:平台端「系统设置 → 小程序配置」中已启用且上传了二维码的小程序, +// 通过公开接口 /site/miniapp 读取;相对地址按接口基址补全。 +const miniApps = ref([]); +const miniQrcodePreview = computed(() => + miniApps.value.map((app) => app.qrcodeSrc), +); + +const resolveAssetUrl = (url) => { + const value = String(url || "").trim().replace(/\\/g, "/"); + if (!value) return ""; + if (/^(https?:\/\/|data:|blob:)/i.test(value)) return value; + const base = String(import.meta.env.VITE_API_BASE_URL || "").replace( + /\/$/, + "", + ); + return `${base}/${value.replace(/^\/+/, "")}`; +}; + +const fetchMiniApps = async () => { + try { + const res = await getSiteMiniApps(); + if (res.code !== 200) return; + miniApps.value = (res.data?.list || []) + .filter((app) => String(app.qrcode_url || "").trim()) + .map((app) => ({ ...app, qrcodeSrc: resolveAssetUrl(app.qrcode_url) })); + } catch (error) { + // 侧栏二维码属于辅助信息,加载失败静默忽略,不影响菜单 + } +}; + const findMenuItem = (menus, targetIndex) => { for (const menu of menus) { if (menu.path === targetIndex) { @@ -445,6 +500,8 @@ watch( ); onMounted(() => { + fetchMiniApps(); + if (!menuStore.menus || menuStore.menus.length === 0) { setTimeout(() => { fetchMenus(); @@ -462,6 +519,8 @@ onUnmounted(() => { diff --git a/backend/src/views/apps/oa/dailyreport/components/ReportEdit.vue b/backend/src/views/apps/oa/dailyreport/components/ReportEdit.vue new file mode 100644 index 0000000..87fcf48 --- /dev/null +++ b/backend/src/views/apps/oa/dailyreport/components/ReportEdit.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/backend/src/views/apps/oa/dailyreport/components/ReportView.vue b/backend/src/views/apps/oa/dailyreport/components/ReportView.vue new file mode 100644 index 0000000..025516b --- /dev/null +++ b/backend/src/views/apps/oa/dailyreport/components/ReportView.vue @@ -0,0 +1,487 @@ + + + + + diff --git a/backend/src/views/apps/oa/dailyreport/index.vue b/backend/src/views/apps/oa/dailyreport/index.vue new file mode 100644 index 0000000..574ad0e --- /dev/null +++ b/backend/src/views/apps/oa/dailyreport/index.vue @@ -0,0 +1,918 @@ + + + + + diff --git a/backend/src/views/basicSettings/applies/index.vue b/backend/src/views/basicSettings/applies/index.vue index 2eb4751..d5e861e 100644 --- a/backend/src/views/basicSettings/applies/index.vue +++ b/backend/src/views/basicSettings/applies/index.vue @@ -40,19 +40,12 @@ - - + + +