diff --git a/api/businessApi.js b/api/businessApi.js index 48892d7..7b6c9bf 100644 --- a/api/businessApi.js +++ b/api/businessApi.js @@ -25,6 +25,18 @@ export function createBusinessApi(prefix, headerFlag) { getMyInfo() { return bizRequest({ url: `${prefix}-auth/my-info`, method: 'GET' }); }, + /** 个人中心 - 我的资料(xk-api GET {prefix}-auth/my-profile,实时库数据) */ + getMyProfile() { + return bizRequest({ url: `${prefix}-auth/my-profile`, method: 'GET' }); + }, + /** 个人中心 - 修改资料(仅昵称/头像,xk-api POST {prefix}-auth/update-my-profile) */ + updateMyProfile(data) { + return bizRequest({ url: `${prefix}-auth/update-my-profile`, method: 'POST', data }); + }, + /** 个人中心 - 修改登录密码(xk-api POST {prefix}-auth/update-password) */ + updateMyPassword(data) { + return bizRequest({ url: `${prefix}-auth/update-password`, method: 'POST', data }); + }, getInputStats() { return bizRequest({ url: `${prefix}-auth/input-stats`, method: 'GET' }); }, diff --git a/api/clinicAdmin.js b/api/clinicAdmin.js index 0e54c18..00a9ca8 100644 --- a/api/clinicAdmin.js +++ b/api/clinicAdmin.js @@ -51,10 +51,65 @@ export function getClinicAdminMyInfo() { return clinicRequest({ url: `${PREFIX}-auth/my-info`, method: 'GET' }); } +/** 个人中心 - 我的资料(xk-api GET clinic-admin-auth/my-profile,实时库数据) */ +export function getClinicAdminMyProfile() { + return clinicRequest({ url: `${PREFIX}-auth/my-profile`, method: 'GET' }); +} + +/** 个人中心 - 修改资料(仅昵称/头像,xk-api POST clinic-admin-auth/update-my-profile) */ +export function updateClinicAdminMyProfile(data) { + return clinicRequest({ url: `${PREFIX}-auth/update-my-profile`, method: 'POST', data }); +} + +/** 个人中心 - 修改登录密码(xk-api POST clinic-admin-auth/update-password) */ +export function updateClinicAdminMyPassword(data) { + return clinicRequest({ url: `${PREFIX}-auth/update-password`, method: 'POST', data }); +} + export function getClinicAdminStoreQr() { return clinicRequest({ url: `${PREFIX}-auth/store-qr`, method: 'GET' }); } +/** + * 工作台看板统计(今日/本月订单、待发货、待审核提现、下单会员数) + * xk-api GET /clinic-admin-dashboard/stats + */ +export function getClinicAdminDashboardStats() { + return clinicRequest({ url: `${PREFIX}-dashboard/stats`, method: 'GET' }); +} + +/** + * 工作台功能入口下发(后台按角色分配的宫格入口,替代前端硬编码) + * xk-api GET /clinic-admin-dashboard/entries + */ +export function getClinicAdminWorkbenchEntries() { + return clinicRequest({ url: `${PREFIX}-dashboard/entries`, method: 'GET' }); +} + +/** + * 功能页用户数据:我的常用 + 最近使用 + * xk-api GET /clinic-admin-dashboard/entry-user-data + */ +export function getClinicAdminEntryUserData() { + return clinicRequest({ url: `${PREFIX}-dashboard/entry-user-data`, method: 'GET' }); +} + +/** + * 收藏/取消收藏功能入口(功能页长按触发),返回 { is_favorite } + * xk-api POST /clinic-admin-dashboard/toggle-favorite-entry + */ +export function toggleClinicAdminFavoriteEntry(code) { + return clinicRequest({ url: `${PREFIX}-dashboard/toggle-favorite-entry`, method: 'POST', data: { code } }); +} + +/** + * 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败) + * xk-api POST /clinic-admin-dashboard/report-entry-usage + */ +export function reportClinicAdminEntryUsage(code) { + return clinicRequest({ url: `${PREFIX}-dashboard/report-entry-usage`, method: 'POST', data: { code } }); +} + /** * 本门店 VIP 开通记录列表 * xk-api GET /clinic-admin-vip/list diff --git a/api/clinicSalesperson.js b/api/clinicSalesperson.js index 4ab0336..5b8c8bc 100644 --- a/api/clinicSalesperson.js +++ b/api/clinicSalesperson.js @@ -22,6 +22,21 @@ export function getClinicSalespersonMyInfo() { return clinicSalespersonRequest({ url: `${AUTH_PREFIX}/my-info`, method: 'GET' }); } +/** 个人中心 - 我的资料(xk-api GET clinic-salesperson-auth/my-profile,实时库数据) */ +export function getClinicSalespersonMyProfile() { + return clinicSalespersonRequest({ url: `${AUTH_PREFIX}/my-profile`, method: 'GET' }); +} + +/** 个人中心 - 修改资料(仅昵称/头像,xk-api POST clinic-salesperson-auth/update-my-profile) */ +export function updateClinicSalespersonMyProfile(data) { + return clinicSalespersonRequest({ url: `${AUTH_PREFIX}/update-my-profile`, method: 'POST', data }); +} + +/** 个人中心 - 修改登录密码(xk-api POST clinic-salesperson-auth/update-password) */ +export function updateClinicSalespersonMyPassword(data) { + return clinicSalespersonRequest({ url: `${AUTH_PREFIX}/update-password`, method: 'POST', data }); +} + export function getClinicSalespersonCommissionList(params) { return clinicSalespersonRequest({ url: `${PREFIX}/commission-list`, method: 'GET', data: params }); } @@ -74,3 +89,35 @@ export function getClinicSalespersonTransferPrescriptionDetail(id) { export function getClinicSalespersonInvitedList(params) { return clinicSalespersonRequest({ url: `${PREFIX}/invited-salesperson-list`, method: 'GET', data: params }); } + +/** + * 推广员工作台功能入口下发(后台按角色分配的宫格入口,替代前端硬编码) + * xk-api GET /clinic-salesperson-dashboard/entries + */ +export function getClinicSalespersonWorkbenchEntries() { + return clinicSalespersonRequest({ url: '/newApi/clinic-salesperson-dashboard/entries', method: 'GET' }); +} + +/** + * 功能页用户数据:我的常用 + 最近使用 + * xk-api GET /clinic-salesperson-dashboard/entry-user-data + */ +export function getClinicSalespersonEntryUserData() { + return clinicSalespersonRequest({ url: '/newApi/clinic-salesperson-dashboard/entry-user-data', method: 'GET' }); +} + +/** + * 收藏/取消收藏功能入口(功能页长按触发),返回 { is_favorite } + * xk-api POST /clinic-salesperson-dashboard/toggle-favorite-entry + */ +export function toggleClinicSalespersonFavoriteEntry(code) { + return clinicSalespersonRequest({ url: '/newApi/clinic-salesperson-dashboard/toggle-favorite-entry', method: 'POST', data: { code } }); +} + +/** + * 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败) + * xk-api POST /clinic-salesperson-dashboard/report-entry-usage + */ +export function reportClinicSalespersonEntryUsage(code) { + return clinicSalespersonRequest({ url: '/newApi/clinic-salesperson-dashboard/report-entry-usage', method: 'POST', data: { code } }); +} diff --git a/api/pharmacistExamine.js b/api/pharmacistExamine.js new file mode 100644 index 0000000..d0aa6f6 --- /dev/null +++ b/api/pharmacistExamine.js @@ -0,0 +1,54 @@ +/** + * 药师审方相关接口(xk-api,取值用 code / result / message,配合 unwrapXkApi) + * + * 老 Yii service/v1/examine/* 已迁移到 xk-api 的 /pharmacist-examine/*, + * 鉴权复用医生端登录 token(ServiceUser),后端中间件强校验药师角色(role=2) + */ +import { + req +} from '@/common/js/index.js'; + +// xk-api GET /pharmacist-examine/list 审方列表(status: 0待审核/1已通过/2未通过;分页 page/pageSize) +export function getExamineList(data) { + return req.request({ + url: '/newApi/pharmacist-examine/list', + method: 'GET', + data + }) +} + +// xk-api GET /pharmacist-examine/detail 审方详情(按处方号) +export function getExamineDetail(data) { + return req.request({ + url: '/newApi/pharmacist-examine/detail', + method: 'GET', + data + }) +} + +// xk-api POST /pharmacist-examine/verify 审方通过/驳回(status=1 通过;status=2 驳回需 reject_reason) +export function verifyExamine(data) { + return req.request({ + url: '/newApi/pharmacist-examine/verify', + method: 'POST', + data + }) +} + +// xk-api GET /pharmacist-examine/source 处方溯源(按处方号) +export function getExamineSource(data) { + return req.request({ + url: '/newApi/pharmacist-examine/source', + method: 'GET', + data + }) +} + +// xk-api GET /pharmacist-examine/use-way 中药用法(煎法)字典 +export function getExamineUseWay(data) { + return req.request({ + url: '/newApi/pharmacist-examine/use-way', + method: 'GET', + data + }) +} diff --git a/api/platformAdmin.js b/api/platformAdmin.js index 8d6bfbc..fb6c451 100644 --- a/api/platformAdmin.js +++ b/api/platformAdmin.js @@ -1,5 +1,63 @@ +import { req } from '@/common/js/index.js'; import { platformAdminApi } from '@/api/businessApi.js'; +import { unwrapClinicRes } from '@/api/clinicAdmin.js'; export { platformAdminApi }; export const getPlatformAdminMyInfo = () => platformAdminApi.getMyInfo(); + +/** + * 平台工作台专属请求助手(带 _platformAdmin 头 + 统一 { res, data, ok } 返回) + * 单独封装(不进 createBusinessApi):dashboard 系列接口仅平台端有,业务员端无此路由 + */ +function platformDashboardRequest(options) { + return req.request({ + ...options, + header: { ...(options.header || {}), _platformAdmin: '1' }, + }).then((res) => { + const data = unwrapClinicRes(res); + const ok = !!(res && Number(res.code) === 0); + return { res, data, ok }; + }); +} + +/** + * 平台工作台看板统计(待审核门店/医生/提现数 + 今日订单概览) + * xk-api GET /platform-admin-dashboard/stats + */ +export function getPlatformAdminDashboardStats() { + return platformDashboardRequest({ url: '/newApi/platform-admin-dashboard/stats', method: 'GET' }); +} + +/** + * 平台工作台功能入口下发(后台按角色分配的宫格入口,替代前端硬编码) + * xk-api GET /platform-admin-dashboard/entries + */ +export function getPlatformAdminWorkbenchEntries() { + return platformDashboardRequest({ url: '/newApi/platform-admin-dashboard/entries', method: 'GET' }); +} + +/** + * 功能页用户数据:我的常用 + 最近使用 + * xk-api GET /platform-admin-dashboard/entry-user-data + */ +export function getPlatformAdminEntryUserData() { + return platformDashboardRequest({ url: '/newApi/platform-admin-dashboard/entry-user-data', method: 'GET' }); +} + +/** + * 收藏/取消收藏功能入口(功能页长按触发),返回 { is_favorite } + * xk-api POST /platform-admin-dashboard/toggle-favorite-entry + */ +export function togglePlatformAdminFavoriteEntry(code) { + return platformDashboardRequest({ url: '/newApi/platform-admin-dashboard/toggle-favorite-entry', method: 'POST', data: { code } }); +} + +/** + * 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败) + * xk-api POST /platform-admin-dashboard/report-entry-usage + */ +export function reportPlatformAdminEntryUsage(code) { + return platformDashboardRequest({ url: '/newApi/platform-admin-dashboard/report-entry-usage', method: 'POST', data: { code } }); +} + export default platformAdminApi; diff --git a/api/salesperson.js b/api/salesperson.js index d7e37cf..60bbfd0 100644 --- a/api/salesperson.js +++ b/api/salesperson.js @@ -1,5 +1,55 @@ +import { req } from '@/common/js/index.js'; import { salespersonApi } from '@/api/businessApi.js'; +import { unwrapClinicRes } from '@/api/clinicAdmin.js'; export const getSalespersonMyInfo = salespersonApi.getMyInfo.bind(salespersonApi); export const getSalespersonInputStats = salespersonApi.getInputStats.bind(salespersonApi); + +/** + * 业务员工作台专属请求助手(带 _salesperson 头 + 统一 { res, data, ok } 返回) + * 单独封装(不进 createBusinessApi):dashboard 系列接口仅业务员端有此路由 + */ +function salespersonDashboardRequest(options) { + return req.request({ + ...options, + header: { ...(options.header || {}), _salesperson: '1' }, + }).then((res) => { + const data = unwrapClinicRes(res); + const ok = !!(res && Number(res.code) === 0); + return { res, data, ok }; + }); +} + +/** + * 业务员工作台功能入口下发(后台按角色分配的宫格入口,替代前端硬编码) + * xk-api GET /salesperson-dashboard/entries + */ +export function getSalespersonWorkbenchEntries() { + return salespersonDashboardRequest({ url: '/newApi/salesperson-dashboard/entries', method: 'GET' }); +} + +/** + * 功能页用户数据:我的常用 + 最近使用 + * xk-api GET /salesperson-dashboard/entry-user-data + */ +export function getSalespersonEntryUserData() { + return salespersonDashboardRequest({ url: '/newApi/salesperson-dashboard/entry-user-data', method: 'GET' }); +} + +/** + * 收藏/取消收藏功能入口(功能页长按触发),返回 { is_favorite } + * xk-api POST /salesperson-dashboard/toggle-favorite-entry + */ +export function toggleSalespersonFavoriteEntry(code) { + return salespersonDashboardRequest({ url: '/newApi/salesperson-dashboard/toggle-favorite-entry', method: 'POST', data: { code } }); +} + +/** + * 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败) + * xk-api POST /salesperson-dashboard/report-entry-usage + */ +export function reportSalespersonEntryUsage(code) { + return salespersonDashboardRequest({ url: '/newApi/salesperson-dashboard/report-entry-usage', method: 'POST', data: { code } }); +} + export default salespersonApi; diff --git a/api/upload.js b/api/upload.js index 41bea39..4a58e83 100644 --- a/api/upload.js +++ b/api/upload.js @@ -3,6 +3,7 @@ import { req } from '@/common/js/index.js'; const SALESPERSON_PREFIX = '/newApi/salesperson-upload/'; const PLATFORM_PREFIX = '/newApi/platform-admin-upload/'; const CLINIC_ADMIN_PREFIX = '/newApi/clinic-admin-upload/'; +const CLINIC_SALESPERSON_PREFIX = '/newApi/clinic-salesperson-upload/'; function uploadChatFileByPrefix(prefix, headerKey, params) { return req.request({ @@ -102,6 +103,52 @@ export function uploadSalespersonManageFileApi(params) { return uploadClinicAdminChatFileApi(params); } +/** + * 个人中心头像上传(xk-api POST {end}-upload/image,UploadController::image) + * 按当前 loginMode 选择四端各自的上传路由与请求头标识; + * uni.uploadFile 返回的 body 是字符串,这里手动 JSON.parse 后按 jok 形态(code/result.url)解包 + * @param {string} filePath 本地临时文件路径 + * @returns {Promise<{ok: boolean, url: string|null, message?: string}>} + */ +export function uploadProfileAvatarApi(filePath) { + const mode = uni.getStorageSync('loginMode'); + let prefix = CLINIC_ADMIN_PREFIX; + let headerKey = '_clinicAdmin'; + if (mode === 'platform_admin') { + prefix = PLATFORM_PREFIX; + headerKey = '_platformAdmin'; + } else if (mode === 'salesperson') { + prefix = SALESPERSON_PREFIX; + headerKey = '_salesperson'; + } else if (mode === 'clinic_salesperson') { + prefix = CLINIC_SALESPERSON_PREFIX; + headerKey = '_clinicSalesperson'; + } + return req.request({ + url: `${prefix}image`, + type: 'upload', + method: 'POST', + filePath, + name: 'file', + formData: {}, + header: { [headerKey]: '1' }, + }).then((res) => { + let body = res; + if (typeof body === 'string') { + try { + body = JSON.parse(body); + } catch (e) { + body = null; + } + } + // 该接口是 xk-api:成功 code=0,业务数据在 result + if (body && Number(body.code) === 0 && body.result && body.result.url) { + return { ok: true, url: body.result.url }; + } + return { ok: false, url: null, message: (body && body.message) || '上传失败' }; + }); +} + function unwrapUploadResult(res) { if (res == null) return null; if (res.result !== undefined && res.result !== null) return res.result; diff --git a/components/admin-my-panel/admin-my-panel.vue b/components/admin-my-panel/admin-my-panel.vue new file mode 100644 index 0000000..ea0a77a --- /dev/null +++ b/components/admin-my-panel/admin-my-panel.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/components/workbench-card-pref/card-pref-entry.vue b/components/workbench-card-pref/card-pref-entry.vue new file mode 100644 index 0000000..8874db3 --- /dev/null +++ b/components/workbench-card-pref/card-pref-entry.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/components/workbench-features/workbench-features.vue b/components/workbench-features/workbench-features.vue new file mode 100644 index 0000000..73f03b4 --- /dev/null +++ b/components/workbench-features/workbench-features.vue @@ -0,0 +1,432 @@ + + + + + diff --git a/components/workbench-user-entries/workbench-user-entries.vue b/components/workbench-user-entries/workbench-user-entries.vue new file mode 100644 index 0000000..ebb8139 --- /dev/null +++ b/components/workbench-user-entries/workbench-user-entries.vue @@ -0,0 +1,176 @@ + + + + + diff --git a/components/xk-list-card/xk-list-card.vue b/components/xk-list-card/xk-list-card.vue new file mode 100644 index 0000000..7650cf8 --- /dev/null +++ b/components/xk-list-card/xk-list-card.vue @@ -0,0 +1,301 @@ + + + + + diff --git a/components/xk-service-card/xk-service-card.vue b/components/xk-service-card/xk-service-card.vue new file mode 100644 index 0000000..a0515d4 --- /dev/null +++ b/components/xk-service-card/xk-service-card.vue @@ -0,0 +1,200 @@ + + + + + diff --git a/pages.json b/pages.json index 44b61c1..5f3f4e9 100644 --- a/pages.json +++ b/pages.json @@ -12,13 +12,6 @@ "navigationStyle": "custom" } }, - { - "path": "pages/login/register", - "style": { - "navigationBarTitleText": "注册", - "navigationStyle": "custom" - } - }, { "path": "pages/workbench/index", "style": { @@ -86,31 +79,12 @@ "enablePullDownRefresh": true } }, - { - "path": "workbench_identity", - "style": { - "navigationBarTitleText": "选择身份", - "navigationStyle": "custom" - } - }, - { - "path": "workbench_reception", - "style": { - "navigationBarTitleText": "加载中..." - } - }, { "path": "workbench_succeed", "style": { "navigationBarTitleText": "加载中..." } }, - { - "path": "workbench_announcement", - "style": { - "navigationBarTitleText": "停诊公告" - } - }, { "path": "workbench_upInfo/select", "style": { @@ -119,44 +93,12 @@ "backgroundColor": "#000" } }, - { - "path": "workbench_evaluation", - "style": { - "navigationBarTitleText": "我的评价", - "enablePullDownRefresh": true - } - }, { "path": "workbench_reason", "style": { "navigationBarTitleText": "选择退诊原因" } }, - { - "path": "workbench_recipe/index", - "style": { - "navigationBarTitleText": "处方详情", - "navigationStyle": "custom" - } - }, - { - "path": "workbench_recipe/add", - "style": { - "navigationBarTitleText": "添加商品" - } - }, - { - "path": "workbench_recipe/addType2", - "style": { - "navigationBarTitleText": "添加商品" - } - }, - { - "path": "workbench_recipe/addProductServicePackage", - "style": { - "navigationBarTitleText": "添加产品服务包" - } - }, { "path": "workbench_recipe/common", "style": { @@ -182,24 +124,6 @@ } } }, - { - "path": "workbench_basicInfo", - "style": { - "navigationBarTitleText": "基础健康信息" - } - }, - { - "path": "workbench_inquiries", - "style": { - "navigationBarTitleText": "问诊记录" - } - }, - { - "path": "workbench_used_language", - "style": { - "navigationBarTitleText": "常用语管理" - } - }, { "path": "workbench_code", "style": { @@ -249,18 +173,6 @@ "navigationBarTitleText": "群发信息" } }, - { - "path": "article_select", - "style": { - "navigationBarTitleText": "选择文章" - } - }, - { - "path": "patient_details", - "style": { - "navigationBarTitleText": "患者详情" - } - }, { "path": "to-store", "style": { @@ -342,13 +254,6 @@ "navigationStyle": "custom" } }, - { - "path": "im", - "style": { - "navigationBarTitleText": "咨询" - - } - }, { "path": "pharmacist_setInfo", "style": { @@ -356,20 +261,6 @@ "navigationStyle": "custom" } }, - { - "path": "change_password", - "style": { - "navigationBarTitleText": "修改登录密码" - - } - }, - { - "path": "pharmacist_prescription", - "style": { - "navigationBarTitleText": "查看处方", - "navigationStyle": "custom" - } - }, { "path": "pharmacist_traceability", "style": { @@ -377,20 +268,6 @@ "navigationStyle": "custom" } }, - { - "path": "pharmacist_access", - "style": { - "navigationBarTitleText": "待接入用户" - } - }, - { - "path": "pharmacist_triage", - "style": { - "navigationBarTitleText": "选择医生", - "enablePullDownRefresh": true - } - - }, { "path": "myrecord-detail", "style": { @@ -406,6 +283,10 @@ "path": "home/index", "style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom" } }, + { + "path": "features/index", + "style": { "navigationBarTitleText": "功能", "navigationStyle": "custom" } + }, { "path": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" } @@ -459,6 +340,7 @@ "style": { "navigationBarTitleText": "订单详情", "navigationStyle": "custom", + "enablePullDownRefresh": true, "usingComponents": { "order-price-percent-adjust-popup": "/subPackages/sub_business_shared/components/OrderPricePercentAdjustPopup" }, @@ -483,8 +365,9 @@ }, { "root": "subPackages/sub_business_shared", "pages": [ + { "path": "card-style/index", "style": { "navigationBarTitleText": "卡片样式", "navigationStyle": "custom" } }, { "path": "order/index", "style": { "navigationBarTitleText": "商品订单", "navigationStyle": "custom", "disableScroll": true } }, - { "path": "order/detail", "style": { "navigationBarTitleText": "订单详情", "navigationStyle": "custom" } }, + { "path": "order/detail", "style": { "navigationBarTitleText": "订单详情", "navigationStyle": "custom", "enablePullDownRefresh": true } }, { "path": "order/trace/index", "style": { "navigationBarTitleText": "订单追溯", "navigationStyle": "custom" } }, { "path": "reconciliation/index", "style": { "navigationBarTitleText": "对账单", "navigationStyle": "custom" } }, { "path": "withdrawal/index", "style": { "navigationBarTitleText": "提现管理", "navigationStyle": "custom" } }, @@ -499,12 +382,14 @@ { "path": "user-patient/index", "style": { "navigationBarTitleText": "会员管理", "navigationStyle": "custom" } }, { "path": "user-patient/patients", "style": { "navigationBarTitleText": "就诊人列表", "navigationStyle": "custom" } }, { "path": "user-patient/detail", "style": { "navigationBarTitleText": "就诊人详情", "navigationStyle": "custom" } }, - { "path": "user-patient/register-detail", "style": { "navigationBarTitleText": "挂号详情", "navigationStyle": "custom" } } + { "path": "user-patient/register-detail", "style": { "navigationBarTitleText": "挂号详情", "navigationStyle": "custom" } }, + { "path": "profile/index", "style": { "navigationBarTitleText": "个人中心", "navigationStyle": "custom" } } ] }, { "root": "subPackages/sub_platform_admin", "pages": [ { "path": "home/index", "style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom" } }, + { "path": "features/index", "style": { "navigationBarTitleText": "功能", "navigationStyle": "custom" } }, { "path": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" } }, { "path": "withdrawal/audit/index", "style": { "navigationBarTitleText": "提现审核", "navigationStyle": "custom" } }, { "path": "store/index", "style": { "navigationBarTitleText": "门店管理", "navigationStyle": "custom" } }, @@ -533,6 +418,7 @@ "root": "subPackages/sub_salesperson", "pages": [ { "path": "home/index", "style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom" } }, + { "path": "features/index", "style": { "navigationBarTitleText": "功能", "navigationStyle": "custom" } }, { "path": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" } }, { "path": "store-input/index", "style": { "navigationBarTitleText": "列表", "navigationStyle": "custom" } }, { "path": "store-input/form", "style": { "navigationBarTitleText": "录入", "navigationStyle": "custom" } }, @@ -558,14 +444,16 @@ } } }, + { + "path": "features/index", + "style": { "navigationBarTitleText": "功能", "navigationStyle": "custom" } + }, { "path": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" } }, - { "path": "earnings/index", "style": { "navigationBarTitleText": "我的收益", "navigationStyle": "custom" } }, { "path": "leads/index", "style": { "navigationBarTitleText": "获客记录", "navigationStyle": "custom" } }, { "path": "commission/index", "style": { "navigationBarTitleText": "服务费记录", "navigationStyle": "custom" } }, { "path": "invitees/index", "style": { "navigationBarTitleText": "我邀请的推广员", "navigationStyle": "custom", "enablePullDownRefresh": true } }, { "path": "invitees/detail", "style": { "navigationBarTitleText": "收益明细", "navigationStyle": "custom" } }, { "path": "settlement/index", "style": { "navigationBarTitleText": "结算记录", "navigationStyle": "custom" } }, - { "path": "transfer-prescription/form", "style": { "navigationBarTitleText": "传方", "navigationStyle": "custom" } }, { "path": "transfer-prescription/list", "style": { "navigationBarTitleText": "传方记录", "navigationStyle": "custom" } } ] }, { @@ -575,11 +463,6 @@ "style": { "navigationBarTitleText": "协议" } - }, { - "path": "web-view", - "style": { - "navigationBarTitleText": "视频" - } }] }, { "root": "subPackages/sub_online_reception", diff --git a/pages/login/register.vue b/pages/login/register.vue deleted file mode 100644 index d6b0f11..0000000 --- a/pages/login/register.vue +++ /dev/null @@ -1,313 +0,0 @@ - - - - - \ No newline at end of file diff --git a/pages/my/index.vue b/pages/my/index.vue index f23efc5..2f655ec 100644 --- a/pages/my/index.vue +++ b/pages/my/index.vue @@ -104,10 +104,6 @@ return { userInfo: uni.getStorageSync('userInfo') || {}, functions: [{ - // name: '我的评价 我的常用方', - // icon: '../../static/image/wdpj.png', - // url: '../../subPackages/sub_workbench/workbench_evaluation' - // }, { name: '我的处方', icon: '../../static/image/wd-cf.png', url: '/subPackages/sub_my/prescriptionList' @@ -129,20 +125,6 @@ } ], items: [ - // { - // name: '常用语管理', - // icon: '../../static/image/wj.png', - // url: '../../subPackages/sub_my/my_commonReply/index' - // }, { - // name: '账号设置我的评价', - // icon: '../../static/image/set.png', - // url: '../../subPackages/sub_pharmacist/pharmacist_setInfo' - // }, - // { - // name: '我的评价', - // icon: '../../static/image/wj.png', - // url: '../../subPackages/sub_workbench/workbench_evaluation' - // }, { name: '常用医嘱管理', icon: '../../static/image/i1.png', diff --git a/pages/my/my-service.vue b/pages/my/my-service.vue index 4400431..04f74b8 100644 --- a/pages/my/my-service.vue +++ b/pages/my/my-service.vue @@ -16,13 +16,6 @@ - - - - - - diff --git a/pages/patient/index.vue b/pages/patient/index.vue index 9e0de7e..9e27225 100644 --- a/pages/patient/index.vue +++ b/pages/patient/index.vue @@ -8,64 +8,53 @@ + - - - - + + - - - - + + - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + 暂无患者,接诊后自动建立档案 + @@ -198,29 +187,60 @@ z-index: 982; } - .function { - image { - width: 80rpx; - height: 80rpx; - } + /* 接诊入口双列卡:白卡大圆角 + 轻阴影,与工作台宫格同规格 */ + .entry-card { + display: flex; + flex-direction: row; + align-items: center; + background: #fff; + border-radius: 24rpx; + padding: 28rpx 24rpx; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03); + transition: all 0.2s ease; } - .l-19 { + .entry-card-hover { + transform: translateY(2rpx); + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); + } + + .entry-icon { + width: 80rpx; + height: 80rpx; + flex-shrink: 0; + } + + /* 入口卡文案分层:标题 + 灰字描述 */ + .entry-info { display: flex; - align-items: center; + flex-direction: column; + margin-left: 20rpx; + min-width: 0; + } + + .entry-name { + font-size: 30rpx; + font-weight: 600; + color: #31353D; + } + + .entry-desc { + font-size: 22rpx; + color: #94A3B8; + margin-top: 4rpx; } .list-new { width: 710rpx; - height: 108rpx; background: #FFFFFF; - border-radius: 12rpx; + border-radius: 24rpx; display: flex; align-items: center; justify-content: space-between; margin: 20rpx 0; - padding: 0 32rpx; + padding: 24rpx 32rpx; color: #333333; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03); .l-l-row { display: flex; @@ -229,9 +249,30 @@ image { width: 56rpx; height: 56rpx; - margin-right: 12rpx; - vertical-align: middle; + flex-shrink: 0; } } } + + /* 患者管理白底容器:标题带内边距,列表项走 flat 卡自带分割线 */ + .patient-panel { + border-radius: 24rpx; + padding: 32rpx 12rpx 16rpx; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03); + } + + .patient-panel-title { + padding: 0 20rpx 8rpx; + } + + /* 空态提示 */ + .patient-empty { + padding: 60rpx 0; + text-align: center; + + text { + font-size: 24rpx; + color: #999; + } + } \ No newline at end of file diff --git a/pages/pharmacist/index.vue b/pages/pharmacist/index.vue index 7ad54d4..f5ab2da 100644 --- a/pages/pharmacist/index.vue +++ b/pages/pharmacist/index.vue @@ -1,95 +1,56 @@ \ No newline at end of file + + /* 分页脚标:加载中 / 没有更多 */ + .load-more { + text-align: center; + padding: 24rpx 0; + + text { + font-size: 24rpx; + color: #A7ABB0; + } + } + + /* 列表容器:灰底页统一 24rpx 横向留白,底部避开固定 tabbar */ + .list-wrap { + padding: 24rpx 24rpx 140rpx; + } + diff --git a/pages/workbench/examine.vue b/pages/workbench/examine.vue index 101c4b8..4dac88b 100644 --- a/pages/workbench/examine.vue +++ b/pages/workbench/examine.vue @@ -63,8 +63,6 @@ }; }, onLoad() { - // this.$go('../../subPackages/sub_workbench/workbench_recipe/index') - // console.log(1); this.screenHeight = uni.getSystemInfoSync().windowHeight }, onShow() { diff --git a/pages/workbench/index.vue b/pages/workbench/index.vue index d970b8a..b9833a9 100644 --- a/pages/workbench/index.vue +++ b/pages/workbench/index.vue @@ -238,126 +238,120 @@ @refresherrefresh="page=1;status = 'loading';loading = true;infoList=[];$store.dispatch('getDocSession')" :refresher-triggered="loading" :refresher-enabled="false" v-if="!loading"> - - + - + - + - + - - - - + 系统消息 + {{ systemList.time }} - - - 你有{{systemList.num}}条未读消息 - + + 你有{{systemList.num}}条未读消息 + + + - - + - + - + - + - - - - + 患者消息 + {{ infoList.time }} - - - 你有{{infoList.num}}名患者待接诊 - + + 你有{{infoList.num}}名患者待接诊 + + + - + - + - + - - - - + 系统消息 + {{ systemList.time }} - - - 点击查看历史消息 - + + 点击查看历史消息 + + + - - + - + - + - - - - + 患者消息 + {{ infoList.time }} - - - 点击查看历史消息 - + + 点击查看历史消息 + + + - - + - + - + - + - - - + 待流转处方消息 - - - 你有{{noticeList.length}}条未读消息 - + + 你有{{noticeList.length}}条未读消息 + + + @@ -1463,6 +1457,13 @@ page { align-items: center; } +/* 消息入口行右侧箭头:垂直居中,暗示整行可点 */ +.wb-entry-arrow { + flex-shrink: 0; + margin-left: 12rpx; + align-self: center; +} + .wb-action-btn { padding: 10rpx 28rpx; font-size: 24rpx; diff --git a/pages1.json b/pages1.json deleted file mode 100644 index 133d360..0000000 --- a/pages1.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "easycom": { - "autoscan": true, - "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue", - "^d-(.*)": "@/components/d-$1/d-$1.vue" - }, - "pages": [{ - "path": "pages/workbench/index", - "style": { - "navigationBarTitleText": "工作台", - "navigationStyle": "custom" - } - }, - { - "path": "pages/patient/index", - "style": { - "navigationBarTitleText": "患者", - "navigationStyle": "custom" - } - }, - { - "path": "pages/article/index", - "style": { - "navigationBarTitleText": "我的文章", - "navigationStyle": "custom", - "enablePullDownRefresh": true - } - }, - { - "path": "pages/my/index", - "style": { - "navigationBarTitleText": "我的", - "navigationStyle": "custom" - } - }, - { - "path": "pages/pharmacist/index", - "style": { - "navigationBarTitleText": "药师", - "navigationStyle": "custom" - } - } - ], - "subPackages": [{ - "root": "subPackages/sub_workbench", - "pages": [{ - "path": "workbench_code", - "style": { - "navigationBarTitleText": "医生码" - } - - }] - }, { - "root": "subPackages/sub_patient", - "pages": [{ - "path": "patient_label", - "style": { - "navigationBarTitleText": "标签管理" - } - }, - { - "path": "patient_massInfo", - "style": { - "navigationBarTitleText": "群发信息" - } - }, - { - "path": "patient_select", - "style": { - "navigationBarTitleText": "群发信息" - } - }, - { - "path": "patient_details", - "style": { - "navigationBarTitleText": "患者详情" - } - } - ] - }, - { - "root": "subPackages/sub_article", - "pages": [{ - "path": "article_release", - "style": { - "navigationBarTitleText": "无标题文档" - } - }, { - "path": "article_draft", - "style": { - "navigationBarTitleText": "我的草稿" - } - }, { - "path": "article_video", - "style": { - "navigationBarTitleText": "无标题文档" - } - } - - ] - } - ], - "tabBar": { - "color": "#666666", - "selectedColor": "#1575FC", - "backgroundColor": "#ffffff", - "borderStyle": "black", - "list": [{ - "pagePath": "pages/workbench/index", - "text": "工作台" - }, - { - "pagePath": "pages/patient/index", - "text": "患者" - }, - { - "pagePath": "pages/article/index", - "text": "我的文章" - }, - { - "pagePath": "pages/my/index", - "text": "我的" - }, - { - "pagePath": "pages/pharmacist/index", - "text": "审方" - } - ] - }, - "globalStyle": { - "navigationBarTitleText": "掌上互联网医院", - "navigationBarBackgroundColor": "#fff", - "navigationBarTextStyle": "black", - "backgroundColor": "#f7f8fa" - } -} \ No newline at end of file diff --git a/subPackages/sub_agreement/web-view.vue b/subPackages/sub_agreement/web-view.vue deleted file mode 100644 index 37146a2..0000000 --- a/subPackages/sub_agreement/web-view.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - - diff --git a/subPackages/sub_business_shared/card-style/index.vue b/subPackages/sub_business_shared/card-style/index.vue new file mode 100644 index 0000000..6d4328f --- /dev/null +++ b/subPackages/sub_business_shared/card-style/index.vue @@ -0,0 +1,278 @@ + + + + + + diff --git a/subPackages/sub_business_shared/common/context.js b/subPackages/sub_business_shared/common/context.js index b08afd5..6dd9608 100644 --- a/subPackages/sub_business_shared/common/context.js +++ b/subPackages/sub_business_shared/common/context.js @@ -30,6 +30,7 @@ export function getPlatformAdminContext() { }, tabList: [ { text: '工作台', iconPath: 'home', selectedIconPath: 'home-fill', pagePath: PLATFORM_HOME }, + { text: '功能', iconPath: 'grid', selectedIconPath: 'grid-fill', pagePath: '/subPackages/sub_platform_admin/features/index' }, { text: '我的', iconPath: 'account', selectedIconPath: 'account-fill', pagePath: PLATFORM_MY }, ], }; @@ -54,6 +55,7 @@ export function getSalespersonContext() { }, tabList: [ { text: '工作台', iconPath: 'home', selectedIconPath: 'home-fill', pagePath: SALESPERSON_HOME }, + { text: '功能', iconPath: 'grid', selectedIconPath: 'grid-fill', pagePath: '/subPackages/sub_salesperson/features/index' }, { text: '我的', iconPath: 'account', selectedIconPath: 'account-fill', pagePath: SALESPERSON_MY }, ], }; @@ -80,6 +82,7 @@ export function getClinicAdminContext() { }, tabList: [ { text: '工作台', iconPath: 'home', selectedIconPath: 'home-fill', pagePath: '/subPackages/sub_clinic_admin/home/index' }, + { text: '功能', iconPath: 'grid', selectedIconPath: 'grid-fill', pagePath: '/subPackages/sub_clinic_admin/features/index' }, { text: '我的', iconPath: 'account', selectedIconPath: 'account-fill', pagePath: '/subPackages/sub_clinic_admin/my/index' }, ], }; diff --git a/subPackages/sub_business_shared/common/profileContext.js b/subPackages/sub_business_shared/common/profileContext.js new file mode 100644 index 0000000..2b147d4 --- /dev/null +++ b/subPackages/sub_business_shared/common/profileContext.js @@ -0,0 +1,80 @@ +/** + * 个人中心多端上下文(sub_business_shared/profile 专用) + * 为什么单独建而不是扩展 resolveBusinessContext:现有 resolveBusinessContext 只覆盖 + * 平台管理员/业务员/诊所管理员 3 端且服务于订单等业务页,这里需要覆盖含诊所推广员的 + * 4 端并聚焦「个人资料」能力,独立文件避免影响既有业务页 + * 四端接口均为 xk-api(jok 形态),API 封装统一返回 { res, data, ok } + */ +import { + getClinicAdminMyProfile, + updateClinicAdminMyProfile, + updateClinicAdminMyPassword, +} from '@/api/clinicAdmin.js'; +import { platformAdminApi, salespersonApi } from '@/api/businessApi.js'; +import { + getClinicSalespersonMyProfile, + updateClinicSalespersonMyProfile, + updateClinicSalespersonMyPassword, +} from '@/api/clinicSalesperson.js'; + +const CONTEXT_MAP = { + clinic_admin: { + mode: 'clinic_admin', + roleFallback: '诊所管理员', + userStorageKey: 'clinic_admin_user', + getMyProfile: getClinicAdminMyProfile, + updateMyProfile: updateClinicAdminMyProfile, + updateMyPassword: updateClinicAdminMyPassword, + }, + platform_admin: { + mode: 'platform_admin', + roleFallback: '平台管理员', + userStorageKey: 'platform_admin_user', + getMyProfile: () => platformAdminApi.getMyProfile(), + updateMyProfile: (data) => platformAdminApi.updateMyProfile(data), + updateMyPassword: (data) => platformAdminApi.updateMyPassword(data), + }, + salesperson: { + mode: 'salesperson', + roleFallback: '业务员', + userStorageKey: 'salesperson_user', + getMyProfile: () => salespersonApi.getMyProfile(), + updateMyProfile: (data) => salespersonApi.updateMyProfile(data), + updateMyPassword: (data) => salespersonApi.updateMyPassword(data), + }, + clinic_salesperson: { + mode: 'clinic_salesperson', + roleFallback: '推广员', + userStorageKey: 'clinic_salesperson_user', + getMyProfile: getClinicSalespersonMyProfile, + updateMyProfile: updateClinicSalespersonMyProfile, + updateMyPassword: updateClinicSalespersonMyPassword, + }, +}; + +/** + * 按当前 loginMode 解析个人中心上下文(默认诊所管理员,避免异常 mode 导致白屏) + */ +export function resolveProfileContext() { + const mode = uni.getStorageSync('loginMode'); + return CONTEXT_MAP[mode] || CONTEXT_MAP.clinic_admin; +} + +/** + * 资料保存成功后把昵称/头像写回各端 user 缓存 + * 为什么要写回:四端「我的」页 onShow 先读本地缓存兜底首屏,不写回的话返回时会闪旧资料 + * 注意推广员端缓存是 { salesperson, store } 嵌套结构,与其余三端平铺结构不同 + * @param {object} ctx resolveProfileContext 返回的上下文 + * @param {object} profile 最新资料(至少含 nick_name / avatar) + */ +export function applyProfileToCache(ctx, profile) { + if (!ctx || !profile) return; + const cached = uni.getStorageSync(ctx.userStorageKey) || {}; + const patch = { nick_name: profile.nick_name || '', avatar: profile.avatar || '' }; + if (ctx.mode === 'clinic_salesperson') { + cached.salesperson = Object.assign({}, cached.salesperson || {}, patch); + uni.setStorageSync(ctx.userStorageKey, cached); + return; + } + uni.setStorageSync(ctx.userStorageKey, Object.assign({}, cached, patch)); +} diff --git a/subPackages/sub_business_shared/common/tabbar.js b/subPackages/sub_business_shared/common/tabbar.js index 389eb90..7244dd4 100644 --- a/subPackages/sub_business_shared/common/tabbar.js +++ b/subPackages/sub_business_shared/common/tabbar.js @@ -1,22 +1,38 @@ +/** + * 诊所管理员端 tabbar 配置(sub_business_shared/clinic-page-layout 用的副本) + * 与 sub_clinic_admin/common/tabbar.js 保持同步:三 tab(工作台/功能/我的)+ uView 图标名 + */ export const TAB_WORKBENCH = 0 -export const TAB_MY = 1 +export const TAB_FEATURES = 1 +export const TAB_MY = 2 + +const ROOT = '/subPackages/sub_clinic_admin' export const CLINIC_TAB_ROUTES = [ - '/subPackages/sub_clinic_admin/home/index', - '/subPackages/sub_clinic_admin/my/index', + `${ROOT}/home/index`, + `${ROOT}/features/index`, + `${ROOT}/my/index`, ] export function getClinicTabList() { return [ { - iconPath: require('@/static/image/w-sf.png'), - selectedIconPath: require('@/static/image/sf.png'), + iconPath: 'home', + selectedIconPath: 'home-fill', text: '工作台', + pagePath: `${ROOT}/home/index`, }, { - iconPath: require('@/static/image/w-wd.png'), - selectedIconPath: require('@/static/image/wd.png'), + iconPath: 'grid', + selectedIconPath: 'grid-fill', + text: '功能', + pagePath: `${ROOT}/features/index`, + }, + { + iconPath: 'account', + selectedIconPath: 'account-fill', text: '我的', + pagePath: `${ROOT}/my/index`, }, ] } diff --git a/subPackages/sub_business_shared/input/InputListPage.vue b/subPackages/sub_business_shared/input/InputListPage.vue index ac8dbcd..d551473 100644 --- a/subPackages/sub_business_shared/input/InputListPage.vue +++ b/subPackages/sub_business_shared/input/InputListPage.vue @@ -4,16 +4,24 @@ - - - {{ item.name }} - {{ statusText(item.status) }} - - {{ item.mobile }} · {{ formatTime(item.created_at) }} - - - - + + + + 暂无记录 @@ -61,6 +69,10 @@ export default { statusText(s) { return { 0: '待审核', 1: '已通过', 2: '已拒绝' }[Number(s)] || '-' }, + /** 状态色映射:与 statusText 对应(橙=待审核 / 绿=通过 / 红=拒绝) */ + statusColor(s) { + return { 0: '#FF7D00', 1: '#00B42A', 2: '#F53F3F' }[Number(s)] || '#999' + }, formatTime(t) { if (!t) return '-' const d = new Date(Number(t) * 1000) @@ -78,14 +90,8 @@ export default { .page-wrap { padding: 24rpx; } .toolbar { margin-bottom: 24rpx; } .btn { background: #6acdbb; color: #fff; font-size: 28rpx; } -.card { background: #fff; padding: 28rpx; border-radius: 16rpx; margin-bottom: 16rpx; } -.row { display: flex; justify-content: space-between; align-items: center; } -.name { font-size: 30rpx; font-weight: 600; } -.status { font-size: 24rpx; } -.s0 { color: #FF7D00; } -.s1 { color: #00B42A; } -.s2 { color: #F53F3F; } -.sub { margin-top: 12rpx; color: #86909C; font-size: 24rpx; } +/* 卡内副文案行(body 插槽内自带样式,组件 rows 样式不作用于插槽) */ +.card-sub { display: block; margin-top: 8rpx; color: #86909C; font-size: 24rpx; } .promoter-row { margin-top: 16rpx; padding-top: 12rpx; border-top: 1rpx solid #f5f5f5; } .empty { text-align: center; color: #86909C; padding: 80rpx 0; } diff --git a/subPackages/sub_business_shared/order/components/ExpressTimeline.vue b/subPackages/sub_business_shared/order/components/ExpressTimeline.vue index 0d7aa14..e6623cb 100644 --- a/subPackages/sub_business_shared/order/components/ExpressTimeline.vue +++ b/subPackages/sub_business_shared/order/components/ExpressTimeline.vue @@ -88,9 +88,13 @@ $color-text-body: #4E5969; $color-text-muted: #86909C; $color-border: #F2F3F5; +/* iOS 卡片规格:与订单详情各面板一致(大圆角 + 发丝线 + 轻阴影) */ .express-panel { background: #ffffff; - padding: 32rpx 40rpx; + border-radius: 32rpx; + border: 1rpx solid rgba(60, 60, 67, 0.08); + box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.04); + padding: 28rpx; margin-bottom: 24rpx; } diff --git a/subPackages/sub_business_shared/order/detail.vue b/subPackages/sub_business_shared/order/detail.vue index 550e748..a923f67 100644 --- a/subPackages/sub_business_shared/order/detail.vue +++ b/subPackages/sub_business_shared/order/detail.vue @@ -2,15 +2,24 @@ - + - + + + + {{ detailExtra.statusText }} + + + 实付 + {{ money(info.total_pay_price) }} + + + 订单号:{{ info.order_no }} - {{ money(info.total_pay_price) }} + 复制 - {{ detailExtra.statusText }} {{ detailExtra.prescriptionTypeText }} {{ detailExtra.deliveryText }} 代支付 @@ -309,11 +318,29 @@ export default { canViewErpMenu() { return this.canViewErp && Number(this.info.prescription_type) === 1 }, + /** 订单状态色:待办橙 / 在途蓝 / 完成绿 / 退款红 / 取消灰(与列表状态语义一致) */ + statusColor() { + const m = { + 0: '#FF7D00', 1: '#FF7D00', 2: '#3B82F6', 3: '#00B42A', 4: '#F53F3F', + 5: '#FF7D00', 6: '#00B42A', 7: '#00B42A', 8: '#F53F3F', 9: '#86909C', + } + return m[Number(this.info.status)] || '#86909C' + }, }, onLoad(q) { this.id = Number(q.id || 0) this.load() }, + /** 下拉刷新:重拉详情(含物流),完成后收起刷新动画 */ + onPullDownRefresh() { + const done = () => uni.stopPullDownRefresh() + const p = this.load() + if (p && p.then) { + p.then(done, done) + } else { + done() + } + }, /** 离开页关闭处方抽屉,避免 page-container 残留遮罩导致列表白屏 */ onHide() { this.closePrescriptionPopup() @@ -344,12 +371,13 @@ export default { this.patientDetailName = this.info.patient || '' this.patientDetailVisible = true }, + /** 拉取订单详情;返回 Promise 供下拉刷新在完成后收起动画 */ load() { if (!this.id) { uni.showToast({ title: '缺少订单信息', icon: 'none' }) return } - this.bizApi.getOrderDetail(this.id).then(w => { + return this.bizApi.getOrderDetail(this.id).then(w => { if (!w.ok) { uni.showToast({ title: '订单加载失败', icon: 'none' }) return @@ -364,6 +392,13 @@ export default { uni.showToast({ title: '订单加载失败', icon: 'none' }) }) }, + /** 复制订单号(状态头卡复制按钮) */ + copyOrderNo() { + uni.setClipboardData({ + data: String(this.info.order_no || ''), + success: () => uni.showToast({ title: '订单号已复制', icon: 'none' }), + }) + }, loadExpress() { this.bizApi.getExpressDetailByOrderId(this.id).then(w => { if (w.ok) this.expressInfo = w.data @@ -435,48 +470,110 @@ export default { diff --git a/subPackages/sub_business_shared/user-patient/index.vue b/subPackages/sub_business_shared/user-patient/index.vue index b94c3f3..6c848b8 100644 --- a/subPackages/sub_business_shared/user-patient/index.vue +++ b/subPackages/sub_business_shared/user-patient/index.vue @@ -13,35 +13,30 @@ 加载中... 暂无用户 - + - - - - {{ item.nickname || '—' }} - - ID:{{ item.id || '—' }} - - + + @@ -121,22 +116,15 @@ export default { background: #6acdbb; color: #fff; padding: 16rpx 28rpx; border-radius: 12rpx; font-size: 26rpx; } -.card { - background: #fff; border-radius: 16rpx; padding: 20rpx 20rpx 16rpx; margin-bottom: 14rpx; -} -.user-row { display: flex; align-items: center; gap: 14rpx; } -.avatar { width: 56rpx; height: 56rpx; border-radius: 50%; background: #e8f5f2; flex-shrink: 0; } -.text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4rpx; } -.name { font-size: 28rpx; color: #111827; font-weight: 500; } -.sub { font-size: 22rpx; color: #9ca3af; } -.chevron { font-size: 32rpx; color: #d1d5db; line-height: 1; } +/* 卡内副文案行(body 插槽自带样式) */ +.card-sub { display: block; margin-top: 4rpx; font-size: 22rpx; color: #9ca3af; } .patients { margin-top: 14rpx; padding-top: 14rpx; border-top: 1rpx solid #eef2f1; display: flex; flex-wrap: wrap; gap: 12rpx; } .patient-tag { - padding: 6rpx 16rpx; border-radius: 8rpx; - background: #f0faf7; border: 1rpx solid #6acdbb; + padding: 6rpx 16rpx; border-radius: 20rpx; + background: #f0f9f7; border: 1rpx solid #c2ece2; } .tag-text { font-size: 22rpx; color: #1a9b88; line-height: 1.4; } .empty-p { font-size: 22rpx; color: #d1d5db; } diff --git a/subPackages/sub_clinic_admin/common/tabbar.js b/subPackages/sub_clinic_admin/common/tabbar.js index 8a3a277..48b7e74 100644 --- a/subPackages/sub_clinic_admin/common/tabbar.js +++ b/subPackages/sub_clinic_admin/common/tabbar.js @@ -1,9 +1,17 @@ +/** + * 诊所管理员端 tabbar 配置(clinic-page-layout 与 sub_salesperson_manage/PageLayout 共用) + * 三 tab:工作台 / 功能 / 我的;图标统一用 uView 图标名(与平台/业务员/推广员三端一致,去掉旧 PNG 依赖) + */ export const TAB_WORKBENCH = 0 -export const TAB_MY = 1 -const ROOT = '/subPackages/sub_clinic_salesperson'; +export const TAB_FEATURES = 1 +export const TAB_MY = 2 + +const ROOT = '/subPackages/sub_clinic_admin' + export const CLINIC_TAB_ROUTES = [ - '/subPackages/sub_clinic_admin/home/index', - '/subPackages/sub_clinic_admin/my/index', + `${ROOT}/home/index`, + `${ROOT}/features/index`, + `${ROOT}/my/index`, ] export function getClinicTabList() { @@ -14,6 +22,12 @@ export function getClinicTabList() { text: '工作台', pagePath: `${ROOT}/home/index`, }, + { + iconPath: 'grid', + selectedIconPath: 'grid-fill', + text: '功能', + pagePath: `${ROOT}/features/index`, + }, { iconPath: 'account', selectedIconPath: 'account-fill', diff --git a/subPackages/sub_clinic_admin/components/clinic-page-layout.vue b/subPackages/sub_clinic_admin/components/clinic-page-layout.vue index 0ab4984..49a17fc 100644 --- a/subPackages/sub_clinic_admin/components/clinic-page-layout.vue +++ b/subPackages/sub_clinic_admin/components/clinic-page-layout.vue @@ -10,10 +10,12 @@ + diff --git a/subPackages/sub_clinic_admin/components/vip-member-card.vue b/subPackages/sub_clinic_admin/components/vip-member-card.vue index 1274b8f..3320fd6 100644 --- a/subPackages/sub_clinic_admin/components/vip-member-card.vue +++ b/subPackages/sub_clinic_admin/components/vip-member-card.vue @@ -1,31 +1,41 @@ @@ -271,78 +313,66 @@ export default { border-radius: 20rpx; } -/* ================= 主体内容区:快捷服务 ================= */ +/* ================= 经营看板:hero 下沉浮白卡(统一工作台看板规格) ================= */ +.dashboard-wrapper { + margin: -30rpx 30rpx 0; + position: relative; + z-index: 11; +} + +.dashboard-card { + background: #fff; + border-radius: 24rpx; + padding: 32rpx 20rpx; + display: grid; + grid-template-columns: repeat(3, 1fr); + row-gap: 32rpx; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03); +} + +.stat-item { + display: flex; + flex-direction: column; + align-items: center; +} + +.stat-label { + font-size: 22rpx; + color: #94A3B8; + margin-bottom: 10rpx; +} + +.stat-value-group { + display: flex; + align-items: baseline; +} + +/* 数值:DIN 数字字体统一看板视觉语言 */ +.stat-value { + font-size: 38rpx; + font-weight: 700; + color: #1E293B; + font-family: "DIN Alternate", sans-serif; +} + +.stat-value.highlight { + color: #059669; +} + +.stat-value.warn { + color: #F97316; +} + +.stat-unit { + font-size: 20rpx; + color: #94A3B8; + margin-left: 4rpx; +} + +/* ================= 主体内容区:个人功能区(分区/宫格样式在 workbench-user-entries 组件内) ================= */ .content-wrapper { margin-top: 30rpx; /* 轻微向上偏移,与顶部区域产生连接感 */ position: relative; z-index: 10; } - -.section-panel { - margin: 0 30rpx 30rpx; - background: transparent; -} - -.panel-header { - margin-bottom: 24rpx; - padding: 0 10rpx; -} - -.panel-title { - font-size: 34rpx; - font-weight: 700; - color: #1E293B; /* 深石板灰 */ -} - -/* 宫格卡片布局:与平台端/推广员端一致的两列 */ -.service-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 20rpx; -} - -.service-card { - background: #FFFFFF; - border-radius: 28rpx; - padding: 30rpx 24rpx; - display: flex; - align-items: center; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02); - transition: all 0.2s ease; - border: 1px solid rgba(0, 0, 0, 0.01); -} - -.service-card-hover { - transform: translateY(-2rpx); - box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06); -} - -.service-icon-box { - width: 76rpx; - height: 76rpx; - border-radius: 22rpx; - display: flex; - align-items: center; - justify-content: center; - margin-right: 20rpx; - flex-shrink: 0; - box-shadow: inset 0 2rpx 4rpx rgba(255, 255, 255, 0.5); /* 顶部微高光,增加拟物质感 */ -} - -.service-info { - display: flex; - flex-direction: column; -} - -.service-name { - font-size: 28rpx; - font-weight: 600; - color: #1E293B; - margin-bottom: 6rpx; -} - -.service-desc { - font-size: 20rpx; - color: #94A3B8; /* 银灰色 */ -} \ No newline at end of file diff --git a/subPackages/sub_clinic_admin/my/index.vue b/subPackages/sub_clinic_admin/my/index.vue index 68c2a71..81e8e0e 100644 --- a/subPackages/sub_clinic_admin/my/index.vue +++ b/subPackages/sub_clinic_admin/my/index.vue @@ -1,76 +1,53 @@ - - diff --git a/subPackages/sub_clinic_admin/my/vip-detail.vue b/subPackages/sub_clinic_admin/my/vip-detail.vue index 199f4ab..3ec33b7 100644 --- a/subPackages/sub_clinic_admin/my/vip-detail.vue +++ b/subPackages/sub_clinic_admin/my/vip-detail.vue @@ -1,28 +1,34 @@ - - diff --git a/subPackages/sub_pharmacist/pharmacist_prescription.vue b/subPackages/sub_pharmacist/pharmacist_prescription.vue deleted file mode 100644 index cdd7d7b..0000000 --- a/subPackages/sub_pharmacist/pharmacist_prescription.vue +++ /dev/null @@ -1,631 +0,0 @@ - - - - - diff --git a/subPackages/sub_pharmacist/pharmacist_traceability.vue b/subPackages/sub_pharmacist/pharmacist_traceability.vue index edcfee5..5e804d8 100644 --- a/subPackages/sub_pharmacist/pharmacist_traceability.vue +++ b/subPackages/sub_pharmacist/pharmacist_traceability.vue @@ -20,7 +20,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -65,11 +65,11 @@ - + - + @@ -92,9 +92,13 @@ - - diff --git a/subPackages/sub_platform_admin/common/context.js b/subPackages/sub_platform_admin/common/context.js index 02c2f34..3a704fa 100644 --- a/subPackages/sub_platform_admin/common/context.js +++ b/subPackages/sub_platform_admin/common/context.js @@ -2,6 +2,7 @@ import { platformAdminApi } from '@/api/businessApi.js'; const BUSINESS_PACKAGE_ROOT = '/subPackages/sub_business_shared'; const PLATFORM_HOME = '/subPackages/sub_platform_admin/home/index'; +const PLATFORM_FEATURES = '/subPackages/sub_platform_admin/features/index'; const PLATFORM_MY = '/subPackages/sub_platform_admin/my/index'; export function getPlatformAdminContext() { @@ -29,6 +30,7 @@ export function getPlatformAdminContext() { }, tabList: [ { text: '工作台', iconPath: 'home', selectedIconPath: 'home-fill', pagePath: PLATFORM_HOME }, + { text: '功能', iconPath: 'grid', selectedIconPath: 'grid-fill', pagePath: PLATFORM_FEATURES }, { text: '我的', iconPath: 'account', selectedIconPath: 'account-fill', pagePath: PLATFORM_MY }, ], }; diff --git a/subPackages/sub_platform_admin/components/business-page-layout.vue b/subPackages/sub_platform_admin/components/business-page-layout.vue index 2cdd6b5..8100857 100644 --- a/subPackages/sub_platform_admin/components/business-page-layout.vue +++ b/subPackages/sub_platform_admin/components/business-page-layout.vue @@ -10,10 +10,12 @@ + diff --git a/subPackages/sub_platform_admin/features/index.vue b/subPackages/sub_platform_admin/features/index.vue new file mode 100644 index 0000000..b7f2374 --- /dev/null +++ b/subPackages/sub_platform_admin/features/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/subPackages/sub_platform_admin/home/index.vue b/subPackages/sub_platform_admin/home/index.vue index 81bf5eb..7939e69 100644 --- a/subPackages/sub_platform_admin/home/index.vue +++ b/subPackages/sub_platform_admin/home/index.vue @@ -2,7 +2,7 @@ - + @@ -10,37 +10,65 @@ {{ displayName }} 欢迎回来,今天也要高效工作 + + {{ todayDay }} + {{ todayMonth }} + - - - - - {{ section.title }} + + + + + 待审核门店 + + {{ dashboard.pending_store_audit }} + + - - - - - - - - - {{ item.label }} - {{ item.desc || '快捷进入' }} - + + 待审核医生 + + {{ dashboard.pending_doctor_audit }} + + + + + 待审核提现 + + {{ dashboard.pending_withdrawal_count }} + + + + + 今日订单 + + {{ dashboard.today_order_count }} + + + + + 今日交易额 + + {{ dashboard.today_order_amount }} + + + + + + @@ -49,165 +77,114 @@ import BusinessPageLayout from '@/subPackages/sub_platform_admin/components/business-page-layout.vue' import { getPlatformAdminContext } from '@/subPackages/sub_platform_admin/common/context.js' import { navigateToInputForm } from '@/subPackages/sub_salesperson/common/inputNavigation.js' -import platformAdminApi from '@/api/platformAdmin.js' - -const ROOT = '/subPackages/sub_platform_admin' -const SALESPERSON_ROOT = '/subPackages/sub_salesperson' +import { getPlatformAdminDashboardStats, getPlatformAdminEntryUserData, reportPlatformAdminEntryUsage } from '@/api/platformAdmin.js' +import { normalizeEntry } from '@/utils/workbenchEntries.js' +import { getCardStyle } from '@/utils/workbenchCardPref.js' export default { components: { BusinessPageLayout }, provide() { return { businessContext: getPlatformAdminContext() } }, data() { + const now = new Date() return { displayName: '', - warehouseMenus: [], - // 预定义的全局主题池,用于动态分配没有明确指定主题的项 - globalThemes: [ - { bg: 'linear-gradient(135deg, #FFF7ED, #FFEDD5)', color: '#F97316' }, // 橙金 - { bg: 'linear-gradient(135deg, #EFF6FF, #DBEAFE)', color: '#3B82F6' }, // 科技蓝 - { bg: 'linear-gradient(135deg, #FAF5FF, #F3E8FF)', color: '#A855F7' }, // 优雅紫 - { bg: 'linear-gradient(135deg, #F0FDF4, #DCFCE7)', color: '#22C55E' }, // 安全绿 - ] + /** hero 右侧日期卡:日 + 月,纯展示用于视觉平衡 */ + todayDay: String(now.getDate()), + todayMonth: (now.getMonth() + 1) + '月', + /** 平台看板数据(接口返回前展示 0,避免布局跳动) */ + dashboard: { + pending_store_audit: 0, + pending_doctor_audit: 0, + pending_withdrawal_count: 0, + today_order_count: 0, + today_order_amount: 0, + }, + /** 我的常用/最近使用原始入口(归一化后存储,行为装饰在 computed 注入保证角标响应式) */ + favRaw: [], + recentRaw: [], + /** 卡片形态偏好:true 长卡一行两个 / false 金刚区宫格(我的页可切换,存本地) */ + cardLong: false, } }, computed: { - sections() { - const shared = '/subPackages/sub_business_shared' - const root = '/subPackages/sub_platform_admin' - - return [ - { - key: 'finance', - title: '财务管理', - items: [ - { - key: 'withdrawal', label: '提现管理', desc: '提现流水查询', path: `${shared}/withdrawal/index`, - icon: 'red-packet-fill', // uView icon - theme: { bg: 'linear-gradient(135deg, #FFF7ED, #FFEDD5)', color: '#F97316' } // 橙金 - }, - { - key: 'withdrawal-audit', label: '提现审核', desc: '处理提现申请', path: `${root}/withdrawal/audit/index`, - icon: 'order', - theme: { bg: 'linear-gradient(135deg, #FEE2E2, #FECACA)', color: '#EF4444' } // 警戒红 - }, - { - key: 'reconciliation', label: '对账单', desc: '财务对账明细', path: `${shared}/reconciliation/index`, - icon: 'file-text-fill', - theme: { bg: 'linear-gradient(135deg, #EFF6FF, #DBEAFE)', color: '#3B82F6' } // 科技蓝 - }, - ], - }, - { - key: 'business', - title: '业务管理', - items: [ - { - key: 'order', label: '商品订单', desc: '全平台订单概览', path: `${shared}/order/index`, - icon: 'bag-fill', - theme: { bg: 'linear-gradient(135deg, #F0FDF4, #DCFCE7)', color: '#22C55E' } // 安全绿 - }, - { - key: 'user-patient', label: '会员管理', desc: '微信用户与就诊人', path: `${shared}/user-patient/index`, - icon: 'account', - theme: { bg: 'linear-gradient(135deg, #FFF7ED, #FFEDD5)', color: '#F97316' } - }, - { - key: 'store-manage', label: '门店管理', desc: '诊所列表与价格配置', path: `${root}/store/index`, - icon: 'home-fill', - theme: { bg: 'linear-gradient(135deg, #ECFEFF, #CFFAFE)', color: '#06B6D4' } - }, - { - key: 'salesperson-manage', label: '推广员管理', desc: '全平台推广员', path: '/subPackages/sub_salesperson_manage/index?mode=platform', - icon: 'account-fill', - theme: { bg: 'linear-gradient(135deg, #FAF5FF, #F3E8FF)', color: '#A855F7' } - } - ], - }, - { - key: 'warehouse', - title: '仓库管理', - // 动态加载的仓库数据,在 onShow 中会进行加工 - items: this.warehouseMenus.length ? this.warehouseMenus : [ - // 提供一个默认的占位符,防止异步加载完成前显示空白 - { - key: 'warehouse-loading', label: '总仓库', desc: '库存管理中心', path: '/subPackages/sub_business_shared/warehouse/index', - icon: 'car-fill', - theme: { bg: 'linear-gradient(135deg, #F3F4F6, #E5E7EB)', color: '#6B7280' } // 占位灰 - } - ] - }, - { - key: 'input-audit', - title: '信息审核', - items: [ - { - key: 'store-audit', label: '门店审核', desc: '新入门店审批', path: `${root}/store-input/audit/index`, - icon: 'home-fill', - theme: { bg: 'linear-gradient(135deg, #FAF5FF, #F3E8FF)', color: '#A855F7' } // 优雅紫 - }, - { - key: 'doctor-audit', label: '医生审核', desc: '入驻医生资质', path: `${root}/doctor-input/audit/index`, - icon: 'account-fill', - theme: { bg: 'linear-gradient(135deg, #EFF6FF, #DBEAFE)', color: '#3B82F6' } // 科技蓝 - }, - ], - }, - { - key: 'input-create', - title: '信息录入', - items: [ - { - key: 'store-list', label: '门店列表', desc: '平台门店档案', path: `${SALESPERSON_ROOT}/store-input/index`, - icon: 'grid-fill', - theme: { bg: 'linear-gradient(135deg, #ECFEFF, #CFFAFE)', color: '#06B6D4' } // 青色 - }, - { - key: 'store-form', label: '门店录入', desc: '新增线下门店', path: `${SALESPERSON_ROOT}/store-input/form`, inputType: 'store', isForm: true, - icon: 'plus-square-fill', - theme: { bg: 'linear-gradient(135deg, #F0FDF4, #DCFCE7)', color: '#22C55E' } // 绿色 - }, - { - key: 'doctor-list', label: '医生列表', desc: '平台医生名册', path: `${SALESPERSON_ROOT}/doctor-input/index`, - icon: 'list-dot', - theme: { bg: 'linear-gradient(135deg, #FFFBEB, #FEF3C7)', color: '#D97706' } // 琥珀色 - }, - { - key: 'doctor-form', label: '医生录入', desc: '新增合作医生', path: `${SALESPERSON_ROOT}/doctor-input/form`, inputType: 'doctor', isForm: true, - icon: 'plus-circle-fill', - theme: { bg: 'linear-gradient(135deg, #FFF7ED, #FFEDD5)', color: '#F97316' } // 橙金 - }, - ], - }, - ] + /** 我的常用(角标/表单预填等行为装饰在这里注入,保证看板数据返回后角标响应式更新) */ + favItems() { + return this.favRaw.map((item) => this.decorateItem(item)) + }, + /** 最近使用 */ + recentItems() { + return this.recentRaw.map((item) => this.decorateItem(item)) }, }, onShow() { const user = uni.getStorageSync('platform_admin_user') || {} this.displayName = user.nick_name || '平台管理员' - - // 加载仓库数据 - platformAdminApi.getWarehouseProductTypeOptions().then(w => { - const options = Array.isArray(w.data) ? w.data : [] - if (!options.length) return - - this.warehouseMenus = options.map((opt, index) => { - const value = opt.value != null ? opt.value : opt.id - const label = opt.label || opt.name || '仓库' - // 为动态仓库分配不同的主题色 - const theme = this.globalThemes[index % this.globalThemes.length] - - return { - key: 'warehouse-' + value, - label, - desc: `${label}库存管理`, // 增强描述 - icon: 'car-fill', // 仓库类目统一使用 uView 的车/物流图标 - theme: theme, - path: `/subPackages/sub_business_shared/warehouse/index?type=${encodeURIComponent(value)}&label=${encodeURIComponent(label)}`, - } - }) - }).catch(() => {}) + // 卡片形态偏好每次 onShow 重读:我的页切换后返回立即生效 + this.cardLong = getCardStyle() === 'long' + this.loadDashboard() + this.loadUserEntries() }, methods: { + /** 拉取我的常用 + 最近使用:失败静默留空(首页有引导条 + 更多功能卡兜底) */ + async loadUserEntries() { + try { + const wrap = await getPlatformAdminEntryUserData() + if (wrap && wrap.ok && wrap.data) { + this.favRaw = this.normalizeList(wrap.data.favorites) + this.recentRaw = this.normalizeList(wrap.data.recents) + } + } catch (e) { + console.error('常用/最近使用加载失败', e) + } + }, + /** 后端入口对象数组 → 渲染项数组(与功能页同一映射) */ + normalizeList(list) { + if (!Array.isArray(list)) return [] + const items = [] + list.forEach((entry) => { + const item = normalizeEntry(entry) + if (item) items.push(item) + }) + return items + }, + /** 按 code 注入本端行为:审核类入口待办角标、录入表单预填标记 */ + decorateItem(item) { + const badgeMap = { + platform_withdrawal_audit: this.dashboard.pending_withdrawal_count, + platform_store_audit: this.dashboard.pending_store_audit, + platform_doctor_audit: this.dashboard.pending_doctor_audit, + } + const formMap = { platform_store_form: 'store', platform_doctor_form: 'doctor' } + const next = { ...item } + if (badgeMap[item.key] != null) { + next.badge = badgeMap[item.key] + } + if (formMap[item.key]) { + next.isForm = true + next.inputType = formMap[item.key] + } + return next + }, + /** 拉取平台看板统计:失败静默保持 0,不阻塞首页其他模块 */ + async loadDashboard() { + try { + const wrap = await getPlatformAdminDashboardStats() + if (wrap && wrap.ok && wrap.data) { + this.dashboard = { ...this.dashboard, ...wrap.data } + } + } catch (e) { + console.error('看板统计加载失败', e) + } + }, + /** 入口点击:静默上报使用(保持最近使用新鲜)→ 表单预填/普通跳转 */ + onEntryTap(item) { + reportPlatformAdminEntryUsage(item.key).catch(() => {}) + this.go(item) + }, + /** 更多功能/空态引导:切到功能 tab(tabbar 页统一走 reLaunch) */ + goFeatures() { + uni.reLaunch({ url: '/subPackages/sub_platform_admin/features/index' }) + }, go(item) { if (item.isForm && item.inputType) { navigateToInputForm(item.path, item.inputType) @@ -278,78 +255,93 @@ export default { display: block; } -/* ================= 主体内容区:快捷服务 ================= */ +/* hero 右侧日期卡:毛玻璃白底小方卡,与推广员端二维码位同规格 */ +.date-chip { + width: 110rpx; + height: 110rpx; + background: rgba(255, 255, 255, 0.18); + border: 1px solid rgba(255, 255, 255, 0.25); + border-radius: 24rpx; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.date-day { + font-size: 44rpx; + font-weight: 700; + color: #fff; + line-height: 1.1; + font-family: "DIN Alternate", sans-serif; +} + +.date-month { + font-size: 22rpx; + color: rgba(255, 255, 255, 0.85); +} + +/* ================= 平台看板:hero 下沉浮白卡(统一工作台看板规格) ================= */ +.dashboard-wrapper { + margin: -30rpx 30rpx 0; + position: relative; + z-index: 11; +} + +.dashboard-card { + background: #fff; + border-radius: 24rpx; + padding: 32rpx 20rpx; + display: grid; + grid-template-columns: repeat(3, 1fr); + row-gap: 32rpx; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03); +} + +.stat-item { + display: flex; + flex-direction: column; + align-items: center; +} + +.stat-label { + font-size: 22rpx; + color: #94A3B8; + margin-bottom: 10rpx; +} + +.stat-value-group { + display: flex; + align-items: baseline; +} + +/* 数值:DIN 数字字体统一看板视觉语言 */ +.stat-value { + font-size: 34rpx; + font-weight: 700; + color: #1E293B; + font-family: "DIN Alternate", sans-serif; +} + +.stat-value.highlight { + color: #059669; +} + +.stat-value.warn { + color: #F97316; +} + +.stat-unit { + font-size: 20rpx; + color: #94A3B8; + margin-left: 4rpx; +} + +/* ================= 主体内容区:个人功能区(分区/宫格样式在 workbench-user-entries 组件内) ================= */ .content-wrapper { margin-top: 30rpx; /* 轻微向上偏移,与顶部区域产生连接感 */ position: relative; z-index: 10; } - -.section-panel { - margin: 0 30rpx 30rpx; /* 增加底部间距 */ - background: transparent; -} - -.panel-header { - margin-bottom: 24rpx; - padding: 0 10rpx; -} - -.panel-title { - font-size: 34rpx; - font-weight: 700; - color: #1E293B; /* 深石板灰 */ -} - -/* 采用与之前页面一致的宫格卡片布局 */ -.service-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 20rpx; -} - -.service-card { - background: #FFFFFF; - border-radius: 28rpx; - padding: 30rpx 24rpx; - display: flex; - align-items: center; - box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.02); - transition: all 0.2s ease; - border: 1px solid rgba(0, 0, 0, 0.01); -} - -.service-card-hover { - transform: translateY(-2rpx); - box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06); -} - -.service-icon-box { - width: 76rpx; - height: 76rpx; - border-radius: 22rpx; - display: flex; - align-items: center; - justify-content: center; - margin-right: 20rpx; - flex-shrink: 0; - box-shadow: inset 0 2rpx 4rpx rgba(255, 255, 255, 0.5); /* 顶部微高光,增加拟物质感 */ -} - -.service-info { - display: flex; - flex-direction: column; -} - -.service-name { - font-size: 28rpx; - font-weight: 600; - color: #1E293B; - margin-bottom: 6rpx; -} - -.service-desc { - font-size: 20rpx; - color: #94A3B8; /* 银灰色 */ -} diff --git a/subPackages/sub_platform_admin/input/InputListPage.vue b/subPackages/sub_platform_admin/input/InputListPage.vue index 5458862..81429db 100644 --- a/subPackages/sub_platform_admin/input/InputListPage.vue +++ b/subPackages/sub_platform_admin/input/InputListPage.vue @@ -4,13 +4,18 @@ - - - {{ item.name }} - {{ statusText(item.status) }} - - {{ item.mobile }} · {{ displayTime(item.created_at) }} - + + 暂无记录 @@ -72,6 +77,10 @@ export default { statusText(s) { return { 0: '待审核', 1: '已通过', 2: '已拒绝' }[Number(s)] || '-' }, + /** 状态色映射:与 statusText 对应(橙=待审核 / 绿=通过 / 红=拒绝) */ + statusColor(s) { + return { 0: '#FF7D00', 1: '#00B42A', 2: '#F53F3F' }[Number(s)] || '#999' + }, displayTime(t) { if (t == null || t === '') return '-' if (typeof t === 'string' && (t.includes('-') || t.includes(':'))) { @@ -98,13 +107,5 @@ export default { .page-wrap { padding: 24rpx; } .toolbar { margin-bottom: 24rpx; } .btn { background: #6acdbb; color: #fff; font-size: 28rpx; } -.card { background: #fff; padding: 28rpx; border-radius: 16rpx; margin-bottom: 16rpx; } -.row { display: flex; justify-content: space-between; align-items: center; } -.name { font-size: 30rpx; font-weight: 600; } -.status { font-size: 24rpx; } -.s0 { color: #FF7D00; } -.s1 { color: #00B42A; } -.s2 { color: #F53F3F; } -.sub { margin-top: 12rpx; color: #86909C; font-size: 24rpx; } .empty { text-align: center; color: #86909C; padding: 80rpx 0; } diff --git a/subPackages/sub_platform_admin/my/index.vue b/subPackages/sub_platform_admin/my/index.vue index 4adb18f..b16f760 100644 --- a/subPackages/sub_platform_admin/my/index.vue +++ b/subPackages/sub_platform_admin/my/index.vue @@ -1,79 +1,38 @@ - - diff --git a/subPackages/sub_platform_admin/store/index.vue b/subPackages/sub_platform_admin/store/index.vue index d86200b..60ca2d2 100644 --- a/subPackages/sub_platform_admin/store/index.vue +++ b/subPackages/sub_platform_admin/store/index.vue @@ -11,29 +11,31 @@ 加载中... 暂无门店 - + - - {{ item.name }} - {{ clinicTypeText(item.clinic_type) }} - - {{ item.position || '暂无地址' }} - - ID {{ item.id }} - 电话 {{ item.mobile }} - - - 推广员可见价格 - 包邮 - 需报备银行卡 - {{ item.bank_card_report_status_text }} - - + + @@ -110,14 +112,7 @@ export default { background: #6ACDBB; color: #fff; padding: 16rpx 32rpx; border-radius: 12rpx; font-size: 26rpx; } .empty { text-align: center; color: #999; padding: 80rpx 0; font-size: 28rpx; } -.card { - background: #fff; border-radius: 16rpx; padding: 24rpx; margin-bottom: 16rpx; -} -.card-hover { opacity: 0.92; } -.card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8rpx; } -.name { font-size: 30rpx; font-weight: 600; color: #1f2937; } -.type-tag { font-size: 22rpx; color: #6ACDBB; background: #f0fbf8; padding: 4rpx 12rpx; border-radius: 8rpx; } -.addr { display: block; font-size: 24rpx; color: #6b7280; margin-bottom: 12rpx; } +.addr { display: block; font-size: 24rpx; color: #6b7280; margin: 8rpx 0 12rpx; } .meta-row { display: flex; gap: 24rpx; font-size: 22rpx; color: #9ca3af; margin-bottom: 12rpx; } .tag-row { display: flex; flex-wrap: wrap; gap: 8rpx; } .mini-tag { diff --git a/subPackages/sub_salesperson/common/context.js b/subPackages/sub_salesperson/common/context.js index cacbb4a..e85accd 100644 --- a/subPackages/sub_salesperson/common/context.js +++ b/subPackages/sub_salesperson/common/context.js @@ -3,6 +3,7 @@ import { getPlatformAdminContext } from '@/subPackages/sub_business_shared/commo const BUSINESS_PACKAGE_ROOT = '/subPackages/sub_business_shared'; const SALESPERSON_HOME = '/subPackages/sub_salesperson/home/index'; +const SALESPERSON_FEATURES = '/subPackages/sub_salesperson/features/index'; const SALESPERSON_MY = '/subPackages/sub_salesperson/my/index'; export function getSalespersonContext() { @@ -24,6 +25,7 @@ export function getSalespersonContext() { }, tabList: [ { text: '工作台', iconPath: 'home', selectedIconPath: 'home-fill', pagePath: SALESPERSON_HOME }, + { text: '功能', iconPath: 'grid', selectedIconPath: 'grid-fill', pagePath: SALESPERSON_FEATURES }, { text: '我的', iconPath: 'account', selectedIconPath: 'account-fill', pagePath: SALESPERSON_MY }, ], }; diff --git a/subPackages/sub_salesperson/components/business-page-layout.vue b/subPackages/sub_salesperson/components/business-page-layout.vue index 30b0a0c..6ebc48c 100644 --- a/subPackages/sub_salesperson/components/business-page-layout.vue +++ b/subPackages/sub_salesperson/components/business-page-layout.vue @@ -11,10 +11,12 @@ + diff --git a/subPackages/sub_salesperson/components/clinic-page-layout.vue b/subPackages/sub_salesperson/components/clinic-page-layout.vue index f8f8aab..c05feb3 100644 --- a/subPackages/sub_salesperson/components/clinic-page-layout.vue +++ b/subPackages/sub_salesperson/components/clinic-page-layout.vue @@ -10,10 +10,12 @@ + diff --git a/subPackages/sub_salesperson/features/index.vue b/subPackages/sub_salesperson/features/index.vue new file mode 100644 index 0000000..0ee8ad6 --- /dev/null +++ b/subPackages/sub_salesperson/features/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/subPackages/sub_salesperson/home/index.vue b/subPackages/sub_salesperson/home/index.vue index 0c53ca7..a2ddf28 100644 --- a/subPackages/sub_salesperson/home/index.vue +++ b/subPackages/sub_salesperson/home/index.vue @@ -35,31 +35,15 @@ - + - - - {{ section.title }} - - - - - - - - - {{ item.label }} - {{ item.desc || '快捷进入' }} - - - - + @@ -67,10 +51,11 @@ - - diff --git a/subPackages/sub_salesperson_manage/index.vue b/subPackages/sub_salesperson_manage/index.vue index b27aae8..9e9b012 100644 --- a/subPackages/sub_salesperson_manage/index.vue +++ b/subPackages/sub_salesperson_manage/index.vue @@ -20,42 +20,46 @@ 加载中... 暂无推广员 + - - {{ item.nick_name || '未知' }} - {{ item.store_name }} + + {{ (item.nick_name || '未')[0] }} + + {{ item.nick_name || '未知' }} + {{ item.store_name || item.phone }} + {{ splitLabel(item.split_type) }} 中药 {{ item.tcm_split }}% - - {{ item.phone }} - - 累计获客 - {{ (item.count && item.count.user_number) || 0 }} + + + + {{ (item.count && item.count.user_number) || 0 }} + 累计获客 - - 待结算 - ¥{{ (item.count && item.count.pending_amount) || '0.00' }} + + ¥{{ (item.count && item.count.pending_amount) || '0.00' }} + 待结算 - - 后台账号 - {{ item.has_admin_account ? '已开通' : '未开通' }} + + {{ item.has_admin_account ? '已开通' : '未开通' }} + 后台账号 - 编辑 - 服务费与结算 - 二维码 - 获客 + 编辑 + 二维码 + 获客 开通后台 + 服务费与结算 @@ -200,27 +204,47 @@ export default { text-align: center; padding: 20rpx; border-radius: 16rpx; font-size: 28rpx; } .loading-tip, .empty { text-align: center; color: #999; padding: 80rpx 0; } +/* 卡片容器:与 xk-list-card 同规格(24rpx 圆角 + 轻阴影) */ .card { - background: #fff; border-radius: 20rpx; padding: 28rpx; margin-bottom: 20rpx; - box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.04); + background: #fff; border-radius: 24rpx; padding: 28rpx 24rpx; margin-bottom: 20rpx; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.03); } -.card-head { display: flex; justify-content: space-between; margin-bottom: 16rpx; } -.name { display: block; font-size: 32rpx; font-weight: 600; } -.store { font-size: 24rpx; color: #999; } -.tags { display: flex; flex-direction: column; gap: 8rpx; align-items: flex-end; } -.tag { font-size: 22rpx; background: #EFF6FF; color: #3B82F6; padding: 4rpx 12rpx; border-radius: 8rpx; } +.card-head { display: flex; justify-content: space-between; align-items: flex-start; } +.head-left { display: flex; align-items: center; min-width: 0; } +/* 首字头像:青绿浅底,与 xk-list-card 兜底头像一致 */ +.avatar-text { + width: 80rpx; height: 80rpx; border-radius: 50%; flex-shrink: 0; + background: #e8f7f3; color: #4db6a8; font-size: 32rpx; font-weight: 600; + display: flex; align-items: center; justify-content: center; margin-right: 20rpx; +} +.head-info { display: flex; flex-direction: column; min-width: 0; } +.name { font-size: 32rpx; font-weight: 500; color: #333; } +.store { font-size: 24rpx; color: #999; margin-top: 4rpx; } +.tags { display: flex; flex-direction: column; gap: 8rpx; align-items: flex-end; flex-shrink: 0; } +.tag { font-size: 22rpx; background: #EFF6FF; color: #3B82F6; padding: 4rpx 12rpx; border-radius: 20rpx; } .tag.tcm { background: #F0FDF4; color: #22C55E; } -.phone { font-size: 26rpx; color: #666; display: block; margin-bottom: 12rpx; } -.stat-row { display: flex; justify-content: space-between; font-size: 26rpx; margin-bottom: 8rpx; } -.num { font-weight: 600; } +/* 统计带:浅灰底圆角内嵌,三列均分,数值加粗突出 */ +.stat-strip { + display: flex; background: #f8fafb; border-radius: 16rpx; + padding: 20rpx 0; margin-top: 20rpx; +} +.stat-cell { + flex: 1; display: flex; flex-direction: column; align-items: center; + border-right: 1rpx solid #eef1f3; + &:last-child { border-right: none; } +} +.stat-num { font-size: 30rpx; font-weight: 600; color: #333; } +.stat-label { font-size: 22rpx; color: #94A3B8; margin-top: 6rpx; } .pending { color: #F97316; } .ok { color: #22C55E; } .warn { color: #EF4444; } -.actions { display: flex; flex-wrap: wrap; gap: 12rpx; margin-top: 20rpx; } +/* 操作区:胶囊按钮,主操作实心青绿、次操作浅底描边、警示操作琥珀 */ +.actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 16rpx; margin-top: 20rpx; } .action-btn { - font-size: 24rpx; padding: 10rpx 20rpx; border-radius: 10rpx; - background: #f5f5f5; color: #333; + font-size: 24rpx; padding: 10rpx 28rpx; border-radius: 30rpx; + font-weight: 500; line-height: 1.4; text-align: center; } +.action-btn.ghost { color: #6ACDBB; background: #f0f9f7; border: 1rpx solid #c2ece2; } .action-btn.primary { background: #6ACDBB; color: #fff; } -.action-btn.warn { background: #FEF3C7; color: #D97706; } +.action-btn.warn { background: #FEF3C7; color: #D97706; border: 1rpx solid #fde68a; } diff --git a/subPackages/sub_workbench/workbench_announcement.vue b/subPackages/sub_workbench/workbench_announcement.vue deleted file mode 100644 index 6e7822f..0000000 --- a/subPackages/sub_workbench/workbench_announcement.vue +++ /dev/null @@ -1,198 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_basicInfo.vue b/subPackages/sub_workbench/workbench_basicInfo.vue deleted file mode 100644 index e0f0798..0000000 --- a/subPackages/sub_workbench/workbench_basicInfo.vue +++ /dev/null @@ -1,63 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_consult.vue b/subPackages/sub_workbench/workbench_consult.vue index df97da0..f19dbfd 100644 --- a/subPackages/sub_workbench/workbench_consult.vue +++ b/subPackages/sub_workbench/workbench_consult.vue @@ -6,31 +6,20 @@ - - - - - - - - - - - {{item.patient}} - {{item.created_at}} - - - {{item.sex %2 != 0 ? '男' : '女'}} - {{item.age + '岁'}} - - - 推广员:{{ item.salesperson_name || '无' }} - - - - + + + @@ -234,24 +223,6 @@ z-index: 99; } - .list { - flex: 1; - display: flex; - flex-direction: column; - margin-left: 30rpx; - - .names { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20rpx; - } - - text { - margin-right: 20rpx; - } - } - .fun { position: fixed; left: 0; diff --git a/subPackages/sub_workbench/workbench_evaluation.vue b/subPackages/sub_workbench/workbench_evaluation.vue deleted file mode 100644 index f9a3859..0000000 --- a/subPackages/sub_workbench/workbench_evaluation.vue +++ /dev/null @@ -1,269 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_identity.vue b/subPackages/sub_workbench/workbench_identity.vue deleted file mode 100644 index ca7adf9..0000000 --- a/subPackages/sub_workbench/workbench_identity.vue +++ /dev/null @@ -1,97 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_inquiries.vue b/subPackages/sub_workbench/workbench_inquiries.vue deleted file mode 100644 index ab72830..0000000 --- a/subPackages/sub_workbench/workbench_inquiries.vue +++ /dev/null @@ -1,83 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_reception.vue b/subPackages/sub_workbench/workbench_reception.vue deleted file mode 100644 index e4738d9..0000000 --- a/subPackages/sub_workbench/workbench_reception.vue +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - diff --git a/subPackages/sub_workbench/workbench_recipe/add.vue b/subPackages/sub_workbench/workbench_recipe/add.vue deleted file mode 100644 index dae6ae7..0000000 --- a/subPackages/sub_workbench/workbench_recipe/add.vue +++ /dev/null @@ -1,644 +0,0 @@ - - - - - \ No newline at end of file diff --git a/subPackages/sub_workbench/workbench_recipe/addProductServicePackage.vue b/subPackages/sub_workbench/workbench_recipe/addProductServicePackage.vue deleted file mode 100644 index 2855f91..0000000 --- a/subPackages/sub_workbench/workbench_recipe/addProductServicePackage.vue +++ /dev/null @@ -1,476 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_recipe/addType2.vue b/subPackages/sub_workbench/workbench_recipe/addType2.vue deleted file mode 100644 index 1dd00a8..0000000 --- a/subPackages/sub_workbench/workbench_recipe/addType2.vue +++ /dev/null @@ -1,1010 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_recipe/components/add-setUsage.vue b/subPackages/sub_workbench/workbench_recipe/components/add-setUsage.vue deleted file mode 100644 index f8cc1a6..0000000 --- a/subPackages/sub_workbench/workbench_recipe/components/add-setUsage.vue +++ /dev/null @@ -1,804 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_recipe/components/diagnose.vue b/subPackages/sub_workbench/workbench_recipe/components/diagnose.vue deleted file mode 100644 index db4a3e9..0000000 --- a/subPackages/sub_workbench/workbench_recipe/components/diagnose.vue +++ /dev/null @@ -1,55 +0,0 @@ - - - - diff --git a/subPackages/sub_workbench/workbench_recipe/index.vue b/subPackages/sub_workbench/workbench_recipe/index.vue deleted file mode 100644 index c074824..0000000 --- a/subPackages/sub_workbench/workbench_recipe/index.vue +++ /dev/null @@ -1,1686 +0,0 @@ - - - - - diff --git a/subPackages/sub_workbench/workbench_used_language.vue b/subPackages/sub_workbench/workbench_used_language.vue deleted file mode 100644 index 4a09138..0000000 --- a/subPackages/sub_workbench/workbench_used_language.vue +++ /dev/null @@ -1,78 +0,0 @@ - - - - - diff --git a/utils/workbenchCardPref.js b/utils/workbenchCardPref.js new file mode 100644 index 0000000..134a336 --- /dev/null +++ b/utils/workbenchCardPref.js @@ -0,0 +1,23 @@ +/** + * 工作台功能卡片形态偏好(长卡/短卡) + * 存本地 storage(已确认不入库):用户在「我的」页切换后,各工作台首页 onShow 时读取生效 + * short = 双列短卡(默认);long = 整行长卡 + */ + +const STORAGE_KEY = 'wb_card_style' + +/** + * 读取卡片形态偏好,异常值一律回落 short,保证布局不会因脏数据坏掉 + */ +export function getCardStyle() { + const value = uni.getStorageSync(STORAGE_KEY) + return value === 'long' ? 'long' : 'short' +} + +/** + * 写入卡片形态偏好 + * @param {'short'|'long'} style + */ +export function setCardStyle(style) { + uni.setStorageSync(STORAGE_KEY, style === 'long' ? 'long' : 'short') +} diff --git a/utils/workbenchEntries.js b/utils/workbenchEntries.js new file mode 100644 index 0000000..cd55e7b --- /dev/null +++ b/utils/workbenchEntries.js @@ -0,0 +1,56 @@ +/** + * 小程序工作台功能入口下发数据的通用组装工具 + * 后端 /xxx-dashboard/entries 返回扁平数组:[{ code, name, description, icon, theme, path, group_name }] + * 这里统一转换成四个工作台首页渲染用的 sections 结构:[{ key, title, items: [{ key, label, desc, icon, theme, path }] }] + * 行为字段(角标/表单预填/弹窗等)由各首页按 code 通过 decorate 回调注入,DB 只管展示与有无 + */ + +/** 未配置主题时的兜底配色(与各端硬编码菜单的占位灰一致) */ +const FALLBACK_THEME = { bg: 'linear-gradient(135deg, #F3F4F6, #E5E7EB)', color: '#6B7280' }; + +/** + * 单条下发入口 → 渲染项归一化(首页 sections 与功能页常用/历史共用同一映射,保证字段一致) + * @param {Object} entry 后端下发的入口对象 + * @returns {Object|null} { key, label, desc, icon, theme, path, group };非法入口返回 null + */ +export function normalizeEntry(entry) { + if (!entry || !entry.code) return null; + return { + key: entry.code, + label: entry.name || '', + desc: entry.description || '', + icon: entry.icon || 'grid-fill', + theme: entry.theme && entry.theme.bg ? entry.theme : FALLBACK_THEME, + path: entry.path || '', + group: entry.group_name || '', + }; +} + +/** + * 下发入口 → sections 结构 + * @param {Array} entries 后端下发的入口数组(已按后台配置排序) + * @param {Function} [decorate] 可选行为装饰回调 (item, entry) => item|null,返回 null 表示丢弃该项 + * @returns {Array} sections;entries 为空/非法时返回空数组(调用方据此回落硬编码菜单) + */ +export function groupEntriesToSections(entries, decorate) { + if (!Array.isArray(entries) || entries.length === 0) return []; + const sections = []; + entries.forEach((entry) => { + let item = normalizeEntry(entry); + if (!item) return; + if (typeof decorate === 'function') { + item = decorate(item, entry); + if (!item) return; + } + const title = entry.group_name || '快捷服务'; + let section = sections.find((s) => s.title === title); + if (!section) { + // key 用分组标题即可(仅作 v-for key,首个出现顺序即分组展示顺序) + section = { key: title, title, items: [] }; + sections.push(section); + } + section.items.push(item); + }); + // 丢弃被 decorate 全部过滤掉的空分组 + return sections.filter((s) => s.items.length > 0); +} diff --git a/{{.Destination}}{{println}}{{end}} b/{{.Destination}}{{println}}{{end}} new file mode 100644 index 0000000..e69de29