From 79d5ae6b66cbc5bfeae653db011bb60095fd7925 Mon Sep 17 00:00:00 2001 From: lzq <357099073@qq.com> Date: Wed, 21 Oct 2026 17:45:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=8B=A5=E5=B9=B2=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/src/api/crmPipeline.js | 8 + backend/src/api/oaDailyReport.js | 81 ++ backend/src/api/site.js | 9 + backend/src/components/CommonAside.vue | 143 ++- .../apps/crm/business/components/detail.vue | 74 +- backend/src/views/apps/crm/business/index.vue | 56 +- .../views/apps/crm/clue/components/detail.vue | 8 + backend/src/views/apps/crm/clue/index.vue | 58 +- backend/src/views/apps/crm/dict.js | 4 +- .../dailyreport/components/ReportDetail.vue | 498 ++++++++++ .../oa/dailyreport/components/ReportEdit.vue | 286 ++++++ .../oa/dailyreport/components/ReportView.vue | 487 ++++++++++ .../src/views/apps/oa/dailyreport/index.vue | 918 ++++++++++++++++++ .../src/views/basicSettings/applies/index.vue | 8 - go/controllers/app_oa_dailyreport.go | 237 +++++ go/controllers/backend_crm_business.go | 80 ++ go/controllers/backend_crm_clue.go | 4 + go/controllers/backend_crm_permission.go | 13 +- go/controllers/backend_oa_dailyreport.go | 261 +++++ go/controllers/index_miniapp.go | 40 + go/controllers/platform_wechat_mini.go | 2 + .../sql/alter_oa_dailyreport_soft_delete.sql | 44 + go/docs/sql/alter_wechat_mini_app_qrcode.sql | 11 + go/docs/sql/create_oa_dailyreport.sql | 66 ++ go/docs/sql/create_wechat_mini_app.sql | 3 +- go/docs/sql/oa_dailyreport_menus.sql | 64 ++ go/models/init.go | 3 + go/models/oa_daily_report.go | 59 ++ go/models/tenant_crm_business.go | 2 +- go/models/wechat_mini.go | 3 +- go/routers/api/api.go | 12 + go/routers/backend/backend.go | 13 + go/routers/index/index.go | 3 + go/services/dailyreport/context.go | 282 ++++++ go/services/dailyreport/report.go | 568 +++++++++++ go/services/dailyreport/team.go | 250 +++++ go/services/wechatmini/config.go | 48 +- platform/src/api/miniApp.js | 3 +- .../components/miniAppSettings.vue | 162 ++++ uniapp/api/oaDailyReport.js | 140 +++ uniapp/pages.json | 21 + uniapp/pages/oa/dailyreport/detail.vue | 573 +++++++++++ uniapp/pages/oa/dailyreport/edit.vue | 458 +++++++++ uniapp/pages/oa/dailyreport/index.vue | 729 ++++++++++++++ uniapp/utils/nav.js | 1 + 45 files changed, 6755 insertions(+), 38 deletions(-) create mode 100644 backend/src/api/oaDailyReport.js create mode 100644 backend/src/api/site.js create mode 100644 backend/src/views/apps/oa/dailyreport/components/ReportDetail.vue create mode 100644 backend/src/views/apps/oa/dailyreport/components/ReportEdit.vue create mode 100644 backend/src/views/apps/oa/dailyreport/components/ReportView.vue create mode 100644 backend/src/views/apps/oa/dailyreport/index.vue create mode 100644 go/controllers/app_oa_dailyreport.go create mode 100644 go/controllers/backend_oa_dailyreport.go create mode 100644 go/controllers/index_miniapp.go create mode 100644 go/docs/sql/alter_oa_dailyreport_soft_delete.sql create mode 100644 go/docs/sql/alter_wechat_mini_app_qrcode.sql create mode 100644 go/docs/sql/create_oa_dailyreport.sql create mode 100644 go/docs/sql/oa_dailyreport_menus.sql create mode 100644 go/models/oa_daily_report.go create mode 100644 go/services/dailyreport/context.go create mode 100644 go/services/dailyreport/report.go create mode 100644 go/services/dailyreport/team.go create mode 100644 uniapp/api/oaDailyReport.js create mode 100644 uniapp/pages/oa/dailyreport/detail.vue create mode 100644 uniapp/pages/oa/dailyreport/edit.vue create mode 100644 uniapp/pages/oa/dailyreport/index.vue 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 @@ - - + + +