diff --git a/.cursor/rules/Business-Shared.mdc b/.cursor/rules/Business-Shared.mdc
new file mode 100644
index 0000000..a32aabe
--- /dev/null
+++ b/.cursor/rules/Business-Shared.mdc
@@ -0,0 +1,32 @@
+---
+description: 后台角色(诊所/平台/业务员)必须复用 sub_business_shared,禁止再复制商品订单等业务页
+alwaysApply: true
+---
+
+# 后台角色共享页(禁止重复造轮子)
+
+诊所管理员 / 平台管理员 / 业务员(含省/市经理)的业务页优先复用 `subPackages/sub_business_shared`,用 `businessMixin` + `resolveBusinessContext` 按 `loginMode` 切 API,不要再复制一套列表/详情。
+
+## 商品订单
+
+- **必须**走 `sub_business_shared/order`(平台、业务员)
+- 诊所管理员继续用历史页 `sub_clinic_admin/order`,**本次不迁、也不要再抄一份**
+- API:平台 `platform-admin-order/*`,业务员 `salesperson-order/*`(`api/businessApi.js`)
+- **数据范围跟 PC**:业务员/省/市经理看名下门店全部订单(后端 `getMyStoreIds()` / `store.code = admin.code`),**禁止**前端再按 `salesperson_id` 过滤
+- **操作跟 PC**:业务员 `canShip/canRefund = false`(`context.js` 的 `bizCap`),详情按钮按能力显隐
+
+```js
+// ❌ BAD:再写一套业务员订单页,或按推广员 ID 滤单
+// ✅ GOOD:工作台入口指向 /subPackages/sub_business_shared/order/index
+```
+
+## 可复用清单(先找再写)
+
+`business-page-layout`、`CollapsibleFilterPanel`、`ListSkeleton`、`InputListPage`、`xk-list-card`、`filterCache`、`pullRefreshMixin`
+
+## 下拉刷新
+
+- 自定义导航 + 内部列表:`scroll-view` 的 `refresher-enabled` + `isRefreshing`(对齐仓库/订单),mixin 用 `pullRefreshMixin`
+- 整页滚动列表:`pages.json` 开 `enablePullDownRefresh` + `onPullDownRefresh` + `uni.stopPullDownRefresh`
+- **禁止**给聊天页(`sub_online_reception/pages/chat`)加下拉刷新
+- 开方编辑器、录入/申请表单、登录、协议、静态成功页不加
diff --git a/api/clinicAdmin.js b/api/clinicAdmin.js
index 6bfb1dd..080132b 100644
--- a/api/clinicAdmin.js
+++ b/api/clinicAdmin.js
@@ -110,6 +110,14 @@ export function toggleClinicAdminFavoriteEntry(code) {
return clinicRequest({ url: `${PREFIX}-dashboard/toggle-favorite-entry`, method: 'POST', data: { code } });
}
+/**
+ * 批量保存我的常用(功能页悬浮编辑 / 首页快捷添加)
+ * xk-api POST /clinic-admin-dashboard/batch-save-favorite-entry
+ */
+export function batchSaveClinicAdminFavoriteEntry(codes) {
+ return clinicRequest({ url: `${PREFIX}-dashboard/batch-save-favorite-entry`, method: 'POST', data: { codes } });
+}
+
/**
* 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败)
* xk-api POST /clinic-admin-dashboard/report-entry-usage
@@ -271,3 +279,8 @@ export function updateWarehousePrice(data) {
export function getWarehouseProductTypeOptions() {
return clinicRequest({ url: `${PREFIX}-warehouse/product-type-options`, method: 'GET' });
}
+
+/** 诊所/药店可见仓库 Tab xk-api GET /clinic-admin-warehouse/warehouse-tabs */
+export function getWarehouseTabs() {
+ return clinicRequest({ url: `${PREFIX}-warehouse/warehouse-tabs`, method: 'GET' });
+}
diff --git a/api/clinicSalesperson.js b/api/clinicSalesperson.js
index 5b8c8bc..a7fe0e0 100644
--- a/api/clinicSalesperson.js
+++ b/api/clinicSalesperson.js
@@ -114,6 +114,14 @@ export function toggleClinicSalespersonFavoriteEntry(code) {
return clinicSalespersonRequest({ url: '/newApi/clinic-salesperson-dashboard/toggle-favorite-entry', method: 'POST', data: { code } });
}
+/**
+ * 批量保存我的常用(功能页悬浮编辑 / 首页快捷添加)
+ * xk-api POST /clinic-salesperson-dashboard/batch-save-favorite-entry
+ */
+export function batchSaveClinicSalespersonFavoriteEntry(codes) {
+ return clinicSalespersonRequest({ url: '/newApi/clinic-salesperson-dashboard/batch-save-favorite-entry', method: 'POST', data: { codes } });
+}
+
/**
* 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败)
* xk-api POST /clinic-salesperson-dashboard/report-entry-usage
diff --git a/api/platformAdmin.js b/api/platformAdmin.js
index f8abe76..9c3cc3f 100644
--- a/api/platformAdmin.js
+++ b/api/platformAdmin.js
@@ -60,6 +60,14 @@ export function togglePlatformAdminFavoriteEntry(code) {
return platformDashboardRequest({ url: '/newApi/platform-admin-dashboard/toggle-favorite-entry', method: 'POST', data: { code } });
}
+/**
+ * 批量保存我的常用(功能页悬浮编辑 / 首页快捷添加)
+ * xk-api POST /platform-admin-dashboard/batch-save-favorite-entry
+ */
+export function batchSavePlatformAdminFavoriteEntry(codes) {
+ return platformDashboardRequest({ url: '/newApi/platform-admin-dashboard/batch-save-favorite-entry', method: 'POST', data: { codes } });
+}
+
/**
* 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败)
* xk-api POST /platform-admin-dashboard/report-entry-usage
diff --git a/api/reception.js b/api/reception.js
index 3a5b8fd..3aeef0d 100644
--- a/api/reception.js
+++ b/api/reception.js
@@ -61,6 +61,15 @@ export function rescheduleAppointmentApi(data) {
})
}
+/** 生成患者代付码 xk-api POST /doctor-reception-wx/proxy-pay-qrcode(order_id;返回 base64 小程序码 + 订单号/金额) */
+export function getProxyPayQrcodeApi(data) {
+ return req.request({
+ url: '/newApi/doctor-reception-wx/proxy-pay-qrcode',
+ method: 'POST',
+ data
+ })
+}
+
/** 医生本人号源日历 xk-api GET /doctor-reception-wx/my-schedule-calendar(改期抽屉选新日期/时段) */
export function getMyScheduleCalendarApi(data) {
return req.request({
diff --git a/api/salesperson.js b/api/salesperson.js
index 60bbfd0..4e2ce5b 100644
--- a/api/salesperson.js
+++ b/api/salesperson.js
@@ -20,6 +20,14 @@ function salespersonDashboardRequest(options) {
});
}
+/**
+ * 业务员工作台首页看板(录入进度 + 名下诊所营业额/处方/挂号)
+ * xk-api GET /salesperson-dashboard/stats?range=today|week|month
+ */
+export function getSalespersonDashboardStats(params = {}) {
+ return salespersonDashboardRequest({ url: '/newApi/salesperson-dashboard/stats', method: 'GET', data: params });
+}
+
/**
* 业务员工作台功能入口下发(后台按角色分配的宫格入口,替代前端硬编码)
* xk-api GET /salesperson-dashboard/entries
@@ -44,6 +52,14 @@ export function toggleSalespersonFavoriteEntry(code) {
return salespersonDashboardRequest({ url: '/newApi/salesperson-dashboard/toggle-favorite-entry', method: 'POST', data: { code } });
}
+/**
+ * 批量保存我的常用(功能页悬浮编辑 / 首页快捷添加)
+ * xk-api POST /salesperson-dashboard/batch-save-favorite-entry
+ */
+export function batchSaveSalespersonFavoriteEntry(codes) {
+ return salespersonDashboardRequest({ url: '/newApi/salesperson-dashboard/batch-save-favorite-entry', method: 'POST', data: { codes } });
+}
+
/**
* 上报功能入口使用(点击跳转时静默调用,调用方无需处理失败)
* xk-api POST /salesperson-dashboard/report-entry-usage
diff --git a/components/account-switch/account-switch-panel.vue b/components/account-switch/account-switch-panel.vue
index d574cb0..c7cf5c6 100644
--- a/components/account-switch/account-switch-panel.vue
+++ b/components/account-switch/account-switch-panel.vue
@@ -1,11 +1,13 @@
+
item.password_matched) || list[0];
},
showPanel() {
+ this.pageGuard = true;
this.$nextTick(() => {
this.visible = true;
});
},
+ releasePageGuard() {
+ this.clearReleaseTimer();
+ this.pageGuard = false;
+ },
+ scheduleReleaseGuard() {
+ this.clearReleaseTimer();
+ this.releaseTimer = setTimeout(() => {
+ this.pageGuard = false;
+ this.releaseTimer = null;
+ }, 350);
+ },
+ clearReleaseTimer() {
+ if (this.releaseTimer) {
+ clearTimeout(this.releaseTimer);
+ this.releaseTimer = null;
+ }
+ },
open(accounts = null, options = {}) {
this.defaultAccountId = options.defaultAccountId ?? null;
this.defaultAccountType = options.defaultAccountType ?? null;
@@ -134,6 +159,7 @@ export default {
},
close() {
this.visible = false;
+ this.scheduleReleaseGuard();
},
handlePageLeave() {
this.close();
diff --git a/components/admin-my-panel/admin-my-panel.vue b/components/admin-my-panel/admin-my-panel.vue
index ea0a77a..aeb7be6 100644
--- a/components/admin-my-panel/admin-my-panel.vue
+++ b/components/admin-my-panel/admin-my-panel.vue
@@ -74,7 +74,7 @@ export default {
methods: {
/** 供页面 onShow 调用:刷新微信绑定状态 */
refreshWxBind() {
- if (this.$refs.wxBindEntry) this.$refs.wxBindEntry.refresh();
+ if (this.$refs.wxBindEntry) return this.$refs.wxBindEntry.refresh();
},
/** 进入共享个人中心页(sub_business_shared 分包页面可被任意分包 navigateTo) */
goProfile() {
diff --git a/components/ai-brief-card/ai-brief-card.vue b/components/ai-brief-card/ai-brief-card.vue
index db1b39e..d7187b1 100644
--- a/components/ai-brief-card/ai-brief-card.vue
+++ b/components/ai-brief-card/ai-brief-card.vue
@@ -1,78 +1,36 @@
-
-
-
-
-
- AI
- 今日简报
- {{ generatedAtText }}
-
-
-
- 重新生成
-
-
-
-
-
-
- AI 正在分析今日门诊数据…
-
-
-
-
- 简报加载失败
- 重试
-
-
-
-
-
-
- {{ chip.value }}
- {{ chip.label }}
-
-
-
- AI 生成失败,请重试
- 重新生成
-
-
-
-
-
-
-
- {{ chip.value }}
- {{ chip.label }}
-
-
-
-
- {{ section.title }}
- {{ section.text }}
-
-
-
- 查看全文
-
-
-
+
+
+
+ AI
+ 今日简报
+ {{ bannerText }}
+
+
-
+
+
-
+
-
+
@@ -60,9 +64,9 @@
-
-
- 暂无常用功能,去功能页长按任意入口即可添加
+
+
+ 暂无常用功能,点此添加
@@ -75,6 +79,7 @@
@click="$emit('more')"
>
+
@@ -86,7 +91,7 @@
* 三段结构与双形态布局完全一致,收敛到主包组件避免四份复制。
* 数据与行为职责划分:
* - 父页面负责拉取 entry-user-data、按 code 注入本端行为(角标/表单预填/传方弹窗)后传入
- * - 本组件只管渲染与转发事件:@item-click(item) 点了某入口、@more 要去功能页
+ * - 本组件只管渲染与转发事件:@item-click(item) 点了某入口、@more 要去功能页、@saved 常用已批量更新
* 点击上报使用也由父页面在 @item-click 里做(各端上报接口不同)
*/
export default {
@@ -98,6 +103,8 @@ export default {
favorites: { type: Array, default: () => [] },
/** 卡片形态:true 长卡一行两个 / false 金刚区宫格 */
cardLong: { type: Boolean, default: false },
+ /** 快捷添加抽屉用:{ getEntries, getUserData, batchSaveFavorites } */
+ api: { type: Object, default: () => ({}) },
},
data() {
return {
@@ -110,6 +117,14 @@ export default {
onItemTap(item) {
this.$emit('item-click', item);
},
+ /** 打开常用编辑抽屉(标题「添加」与空态共用) */
+ openEditor() {
+ if (this.$refs.favEditor) this.$refs.favEditor.open();
+ },
+ /** 批量保存成功:通知首页重拉常用/最近,角标等装饰仍由父页注入 */
+ onEditorSaved() {
+ this.$emit('saved');
+ },
},
};
@@ -119,9 +134,29 @@ export default {
margin: 0 30rpx 30rpx;
}
.wue-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
margin-bottom: 24rpx;
padding: 0 10rpx;
}
+.wue-add {
+ display: flex;
+ align-items: center;
+ padding: 8rpx 16rpx;
+ border-radius: 28rpx;
+ border: 1rpx solid rgba(106, 205, 187, 0.3);
+ box-shadow: 0 0 10rpx rgba(106, 205, 187, 0.16);
+ background: rgba(106, 205, 187, 0.08);
+ text {
+ margin-left: 6rpx;
+ font-size: 24rpx;
+ color: #6ACDBB;
+ }
+}
+.wue-add-hover {
+ opacity: 0.75;
+}
/* 分区标题:对齐四首页既有 panel-title 规格 */
.wue-title {
font-size: 34rpx;
diff --git a/pages.json b/pages.json
index 5f3f4e9..7d6a6d6 100644
--- a/pages.json
+++ b/pages.json
@@ -35,7 +35,8 @@
"path": "pages/patient/index",
"style": {
"navigationBarTitleText": "患者",
- "navigationStyle": "custom"
+ "navigationStyle": "custom",
+ "enablePullDownRefresh": true
}
},
{
@@ -281,7 +282,7 @@
"root": "subPackages/sub_clinic_admin",
"pages": [{
"path": "home/index",
- "style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom" }
+ "style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom", "enablePullDownRefresh": true }
},
{
"path": "features/index",
@@ -289,7 +290,7 @@
},
{
"path": "my/index",
- "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" }
+ "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom", "enablePullDownRefresh": true }
},
{
"path": "my/vip-detail",
@@ -297,11 +298,11 @@
},
{
"path": "withdrawal/index",
- "style": { "navigationBarTitleText": "提现管理", "navigationStyle": "custom" }
+ "style": { "navigationBarTitleText": "提现管理", "navigationStyle": "custom", "enablePullDownRefresh": true }
},
{
"path": "withdrawal/settlement/index",
- "style": { "navigationBarTitleText": "结算记录", "navigationStyle": "custom" }
+ "style": { "navigationBarTitleText": "结算记录", "navigationStyle": "custom", "enablePullDownRefresh": true }
},
{
"path": "withdrawal/settlement/detail",
@@ -309,7 +310,7 @@
},
{
"path": "withdrawal/account-change/index",
- "style": { "navigationBarTitleText": "资金变动", "navigationStyle": "custom" }
+ "style": { "navigationBarTitleText": "资金变动", "navigationStyle": "custom", "enablePullDownRefresh": true }
},
{
"path": "withdrawal/apply",
@@ -325,7 +326,7 @@
},
{
"path": "reconciliation/index",
- "style": { "navigationBarTitleText": "对账单", "navigationStyle": "custom" }
+ "style": { "navigationBarTitleText": "对账单", "navigationStyle": "custom", "enablePullDownRefresh": true }
},
{
"path": "order/index",
@@ -369,18 +370,18 @@
{ "path": "order/index", "style": { "navigationBarTitleText": "商品订单", "navigationStyle": "custom", "disableScroll": true } },
{ "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" } },
+ { "path": "reconciliation/index", "style": { "navigationBarTitleText": "对账单", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "withdrawal/index", "style": { "navigationBarTitleText": "提现管理", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "withdrawal/apply", "style": { "navigationBarTitleText": "申请提现", "navigationStyle": "custom" } },
{ "path": "withdrawal/card-edit", "style": { "navigationBarTitleText": "编辑账户", "navigationStyle": "custom" } },
{ "path": "withdrawal/record-detail", "style": { "navigationBarTitleText": "提现详情", "navigationStyle": "custom" } },
- { "path": "withdrawal/settlement/index", "style": { "navigationBarTitleText": "结算记录", "navigationStyle": "custom" } },
+ { "path": "withdrawal/settlement/index", "style": { "navigationBarTitleText": "结算记录", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "withdrawal/settlement/detail", "style": { "navigationBarTitleText": "结算明细", "navigationStyle": "custom" } },
- { "path": "withdrawal/account-change/index", "style": { "navigationBarTitleText": "资金变动", "navigationStyle": "custom" } },
- { "path": "warehouse/index", "style": { "navigationBarTitleText": "仓库管理", "navigationStyle": "custom" } },
+ { "path": "withdrawal/account-change/index", "style": { "navigationBarTitleText": "资金变动", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "warehouse/index", "style": { "navigationBarTitleText": "仓库管理", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "warehouse/detail", "style": { "navigationBarTitleText": "药品详情", "navigationStyle": "custom" } },
- { "path": "user-patient/index", "style": { "navigationBarTitleText": "会员管理", "navigationStyle": "custom" } },
- { "path": "user-patient/patients", "style": { "navigationBarTitleText": "就诊人列表", "navigationStyle": "custom" } },
+ { "path": "user-patient/index", "style": { "navigationBarTitleText": "会员管理", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "user-patient/patients", "style": { "navigationBarTitleText": "就诊人列表", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "user-patient/detail", "style": { "navigationBarTitleText": "就诊人详情", "navigationStyle": "custom" } },
{ "path": "user-patient/register-detail", "style": { "navigationBarTitleText": "挂号详情", "navigationStyle": "custom" } },
{ "path": "profile/index", "style": { "navigationBarTitleText": "个人中心", "navigationStyle": "custom" } }
@@ -388,28 +389,28 @@
}, {
"root": "subPackages/sub_platform_admin",
"pages": [
- { "path": "home/index", "style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom" } },
+ { "path": "home/index", "style": { "navigationBarTitleText": "工作台", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "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" } },
+ { "path": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "withdrawal/audit/index", "style": { "navigationBarTitleText": "提现审核", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "store/index", "style": { "navigationBarTitleText": "门店管理", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "store/detail", "style": { "navigationBarTitleText": "门店详情", "navigationStyle": "custom" } },
{ "path": "store/edit", "style": { "navigationBarTitleText": "编辑诊所", "navigationStyle": "custom" } },
{ "path": "store/drug-price", "style": { "navigationBarTitleText": "药品价格", "navigationStyle": "custom" } },
{ "path": "store/consultation", "style": { "navigationBarTitleText": "在线复诊", "navigationStyle": "custom" } },
- { "path": "store-input/audit/index", "style": { "navigationBarTitleText": "门店审核", "navigationStyle": "custom" } },
+ { "path": "store-input/audit/index", "style": { "navigationBarTitleText": "门店审核", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "store-input/audit/detail", "style": { "navigationBarTitleText": "审核详情", "navigationStyle": "custom" } },
- { "path": "doctor-input/audit/index", "style": { "navigationBarTitleText": "医生审核", "navigationStyle": "custom" } },
+ { "path": "doctor-input/audit/index", "style": { "navigationBarTitleText": "医生审核", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "doctor-input/audit/detail", "style": { "navigationBarTitleText": "审核详情", "navigationStyle": "custom" } }
]
}, {
"root": "subPackages/sub_salesperson_manage",
"pages": [
- { "path": "index", "style": { "navigationBarTitleText": "推广员管理", "navigationStyle": "custom" } },
+ { "path": "index", "style": { "navigationBarTitleText": "推广员管理", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "form", "style": { "navigationBarTitleText": "推广员", "navigationStyle": "custom" } },
- { "path": "drug-commission/index", "style": { "navigationBarTitleText": "药品佣金", "navigationStyle": "custom" } },
- { "path": "leads/index", "style": { "navigationBarTitleText": "获客记录", "navigationStyle": "custom" } },
- { "path": "commission/index", "style": { "navigationBarTitleText": "服务费与结算", "navigationStyle": "custom" } },
+ { "path": "drug-commission/index", "style": { "navigationBarTitleText": "药品佣金", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "leads/index", "style": { "navigationBarTitleText": "获客记录", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "commission/index", "style": { "navigationBarTitleText": "服务费与结算", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "settlement/preview", "style": { "navigationBarTitleText": "按时间段结算", "navigationStyle": "custom" } },
{ "path": "settlement/confirm", "style": { "navigationBarTitleText": "确认结算", "navigationStyle": "custom" } },
{ "path": "settlement/detail", "style": { "navigationBarTitleText": "结算详情", "navigationStyle": "custom" } }
@@ -419,12 +420,12 @@
"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": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "store-input/index", "style": { "navigationBarTitleText": "列表", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "store-input/form", "style": { "navigationBarTitleText": "录入", "navigationStyle": "custom" } },
{ "path": "store-input/detail", "style": { "navigationBarTitleText": "录入详情", "navigationStyle": "custom" } },
{ "path": "store-bank-card/report", "style": { "navigationBarTitleText": "银行卡报备", "navigationStyle": "custom" } },
- { "path": "doctor-input/index", "style": { "navigationBarTitleText": "列表", "navigationStyle": "custom" } },
+ { "path": "doctor-input/index", "style": { "navigationBarTitleText": "列表", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "path": "doctor-input/form", "style": { "navigationBarTitleText": "录入", "navigationStyle": "custom" } },
{ "path": "doctor-input/detail", "style": { "navigationBarTitleText": "预填详情", "navigationStyle": "custom" } }
]
@@ -436,6 +437,7 @@
"style": {
"navigationBarTitleText": "工作台",
"navigationStyle": "custom",
+ "enablePullDownRefresh": true,
"usingComponents": {
"transfer-patient-drawer": "/subPackages/sub_workbench/prescription_v2/components/modals/TransferPatientDrawer"
},
@@ -448,13 +450,13 @@
"path": "features/index",
"style": { "navigationBarTitleText": "功能", "navigationStyle": "custom" }
},
- { "path": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom" } },
- { "path": "leads/index", "style": { "navigationBarTitleText": "获客记录", "navigationStyle": "custom" } },
- { "path": "commission/index", "style": { "navigationBarTitleText": "服务费记录", "navigationStyle": "custom" } },
+ { "path": "my/index", "style": { "navigationBarTitleText": "我的", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "leads/index", "style": { "navigationBarTitleText": "获客记录", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "commission/index", "style": { "navigationBarTitleText": "服务费记录", "navigationStyle": "custom", "enablePullDownRefresh": true } },
{ "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/list", "style": { "navigationBarTitleText": "传方记录", "navigationStyle": "custom" } }
+ { "path": "invitees/detail", "style": { "navigationBarTitleText": "收益明细", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "settlement/index", "style": { "navigationBarTitleText": "结算记录", "navigationStyle": "custom", "enablePullDownRefresh": true } },
+ { "path": "transfer-prescription/list", "style": { "navigationBarTitleText": "传方记录", "navigationStyle": "custom", "enablePullDownRefresh": true } }
]
}, {
"root": "subPackages/sub_agreement",
@@ -470,7 +472,8 @@
"path": "pages/list",
"style": {
"navigationBarTitleText": "在线接诊",
- "navigationStyle": "custom"
+ "navigationStyle": "custom",
+ "enablePullDownRefresh": true
}
}, {
"path": "pages/chat",
diff --git a/pages/login/index.vue b/pages/login/index.vue
index c1cd878..b56bc12 100644
--- a/pages/login/index.vue
+++ b/pages/login/index.vue
@@ -25,7 +25,11 @@ export default {
onShow() {
if (this.pendingAccountSelect) return;
this.$refs.doctorLogin?.loadWxConfig?.();
- redirectIfLoggedIn();
+ // 等当前页进栈后再跳,避免启动阶段 reLaunch 触发 appLaunch with non-empty page stack
+ this.$nextTick(() => {
+ if (this.pendingAccountSelect) return;
+ redirectIfLoggedIn();
+ });
},
methods: {
openAccountPicker({ accounts, defaultAccountId, defaultAccountType }) {
diff --git a/pages/patient/index.vue b/pages/patient/index.vue
index 9e27225..7d1ca54 100644
--- a/pages/patient/index.vue
+++ b/pages/patient/index.vue
@@ -46,9 +46,9 @@
@@ -127,7 +127,8 @@
})
.then((res) => {
if (res.errcode == 0) {
- this.list = this.page === 1 ? res.data.list : [...this.list, ...res.data.list];
+ const rows = (res.data.list || []).map((item) => this.normalizeItem(item));
+ this.list = this.page === 1 ? rows : [...this.list, ...rows];
this.totalPage = res.data.pagination.totalPage;
if (this.page >= this.totalPage) {
this.status = "nomore";
@@ -153,6 +154,22 @@
this.loading2 = false;
});
},
+ /**
+ * 列表展示字段提前算好:部分患者 user 为 null,模板读 user.avatarurl 会直接崩
+ * 微信模板禁止 ?. / ??,头像和性别文案统一在这里兜底
+ */
+ normalizeItem(item) {
+ const isFemale = item.sex % 2 == 0;
+ const user = item.user || {};
+ const fallback = isFemale
+ ? (this.girl || require('../../static/image/nv.png'))
+ : (this.male || require('../../static/image/nan.png'));
+ return {
+ ...item,
+ card_avatar: user.avatarurl || fallback,
+ card_meta: (isFemale ? '女' : '男') + ' · ' + (item.age || '-') + '岁',
+ };
+ },
toDetail(id) {
uni.navigateTo({
url: '/subPackages/sub_patient/patient_detail?id=' + id
diff --git a/pages/pharmacist/index.vue b/pages/pharmacist/index.vue
index f5ab2da..9812e3c 100644
--- a/pages/pharmacist/index.vue
+++ b/pages/pharmacist/index.vue
@@ -20,7 +20,14 @@
-
+
-
-
+
+
@@ -113,7 +113,7 @@
{{ item.name }}
@@ -155,8 +155,8 @@
到店开方、处理线下挂号
@@ -421,13 +421,14 @@
-
+
+
@@ -522,7 +523,7 @@ export default {
name: '已结束',
color: '#C4C7CC'
},
- 3: {
+ 4: {
name: '已取消',
color: '#C4C7CC'
}
@@ -569,6 +570,10 @@ export default {
appointmentUpcoming: { total: 0, days: [] },
apptDrawerShow: false,
apptDefaultDate: '',
+ // AI 简报全文弹层是否打开(打开时隐藏自定义 tabbar,避免抽屉被挡住)
+ briefPopupShow: false,
+ // 系统配置总开关:默认不展示,看板接口确认开启后再挂载简报卡
+ aiBriefEnabled: false,
};
},
watch: {
@@ -594,6 +599,20 @@ export default {
const contentPx = typeof uni.upx2px === 'function' ? uni.upx2px(312) : 156;
return this.statusBarHeight + this.navbarHeight + contentPx;
},
+ /** 未来7天 pill:接口偶发不带 days 时给空数组,避免渲染层对 undefined 做迭代报错 */
+ upcomingDayList() {
+ const days = this.appointmentUpcoming && this.appointmentUpcoming.days;
+ return Array.isArray(days) ? days : [];
+ },
+ /**
+ * 线下接诊角标:优先用今日看板(已剔除未到就诊日的预约),避免 Yii info 把后天预约算进来
+ */
+ offlineWaitAccept() {
+ const todayStats = this.statsCache && this.statsCache.today;
+ if (todayStats) return Number(todayStats.wait_accept) || 0;
+ if (this.statsRange === 'today') return Number(this.workbenchStats.wait_accept) || 0;
+ return Number(this.doctorInfo && this.doctorInfo.wait_accept) || 0;
+ },
},
onLoad() {
this.initStatsRangeFromStorage();
@@ -641,10 +660,6 @@ export default {
},
refreshWorkbenchData() {
const silentStats = this.statsInitialized || this.hasStatsCache(this.statsRange);
- // AI 简报随工作台一起刷新:组件内部按「门店+日期」去重,同店同天已拉过会直接跳过
- if (this.$refs.aiBrief) {
- this.$refs.aiBrief.fetchBrief(false);
- }
return Promise.all([
this.getNotice(),
this.getInfo(),
@@ -652,7 +667,18 @@ export default {
this.getList(),
this.getAcceptingPatientList(),
this.fetchOnlineConsultationConfig(),
- this.fetchWorkbenchStats({ silent: silentStats })
+ this.fetchWorkbenchStats({ silent: silentStats }).then(() => {
+ // 先确认开关再拉简报:关闭时不请求,避免无谓生成
+ this.$nextTick(() => {
+ if (this.aiBriefEnabled && this.$refs.aiBrief) {
+ this.$refs.aiBrief.fetchBrief(false);
+ }
+ });
+ // 角标用今日待接诊;当前看板不是「今日」时补拉一份 today 缓存
+ if (this.statsRange !== 'today') {
+ return this.fetchWorkbenchStats({ silent: true, range: 'today' });
+ }
+ })
]).then(() => {
this.notifyWorkbenchRefreshed();
});
@@ -855,6 +881,10 @@ export default {
if (Number.isNaN(num)) return '0.000'
return num.toFixed(3)
},
+ /** AI 简报弹层开合:打开时隐藏自定义 tabbar,避免抽屉底部「知道了」被挡住 */
+ onBriefPopupChange(show) {
+ this.briefPopupShow = !!show;
+ },
/** 打开未来7天预约明细抽屉;date 为空看全部,点某天卡格预筛选该天 */
openApptDrawer(date) {
this.apptDefaultDate = date || '';
@@ -889,6 +919,8 @@ export default {
days: payload.appointment_upcoming.days || [],
};
}
+ // 简报总开关随看板下发,关闭则卸掉卡片
+ this.aiBriefEnabled = payload.ai_daily_brief_enabled === true || payload.ai_daily_brief_enabled === 1;
this.statsInitialized = true;
}
}).catch(() => {
@@ -1040,7 +1072,7 @@ export default {
},
acceptingStatusLabel(item) {
const st = Number(item.status);
- const m = { 1: '待接诊', 2: '接诊中', 3: '已结束' };
+ const m = { 1: '待接诊', 2: '接诊中', 3: '已结束', 4: '已取消', 7: '已拒诊' };
return m[st] || '接诊中';
},
acceptingStatusColor(item) {
diff --git a/subPackages/sub_business_shared/common/display.js b/subPackages/sub_business_shared/common/display.js
index dfe1a0c..cb9d403 100644
--- a/subPackages/sub_business_shared/common/display.js
+++ b/subPackages/sub_business_shared/common/display.js
@@ -515,6 +515,8 @@ export function mapWarehouseRow(item, warehouseType = 'store') {
statusText: warehouseStatusText(item.status),
isOnShelf: item.status === 2,
pinyin: drug.pinyin || '-',
+ // 绑定配送仓:商家不可改价,列表/详情按钮置灰
+ priceLocked: Number(item.has_delivery_warehouse) === 1,
_raw: item,
}
}
diff --git a/subPackages/sub_business_shared/common/pullRefreshMixin.js b/subPackages/sub_business_shared/common/pullRefreshMixin.js
new file mode 100644
index 0000000..cdd694a
--- /dev/null
+++ b/subPackages/sub_business_shared/common/pullRefreshMixin.js
@@ -0,0 +1,62 @@
+/**
+ * 列表/看板下拉刷新:自定义导航用 scroll-view refresher,整页滚动用 onPullDownRefresh。
+ * 页面需实现 reload();请求结束务必调 finishRefresh(),否则转圈不收起。
+ * 最短转圈 400ms:接口太快时微信 refresher 动画来不及展开,看起来像「下拉没反应」。
+ */
+const MIN_REFRESH_MS = 400
+
+export default {
+ data() {
+ return {
+ isRefreshing: false,
+ }
+ },
+ methods: {
+ /**
+ * 统一走 reload();若返回 Promise 则在 finally 收起转圈
+ */
+ runPullRefresh() {
+ this.isRefreshing = true
+ const started = Date.now()
+ const done = () => {
+ const wait = Math.max(0, MIN_REFRESH_MS - (Date.now() - started))
+ setTimeout(() => this.finishRefresh(), wait)
+ }
+ if (typeof this.reload !== 'function') {
+ done()
+ return
+ }
+ try {
+ const ret = this.reload()
+ if (ret && typeof ret.then === 'function') {
+ ret.finally(done)
+ } else {
+ this.$nextTick(done)
+ }
+ } catch (e) {
+ done()
+ }
+ },
+ /**
+ * scroll-view 下拉:先亮转圈再重拉当前列表
+ */
+ onRefresherRefresh() {
+ this.runPullRefresh()
+ },
+ /**
+ * 整页原生下拉:重拉后必须 stop,否则系统转圈卡住
+ */
+ onPullDownRefresh() {
+ this.runPullRefresh()
+ },
+ /**
+ * 请求 finally 里关掉两种转圈
+ */
+ finishRefresh() {
+ this.isRefreshing = false
+ try {
+ uni.stopPullDownRefresh()
+ } catch (e) { /* 未开启原生下拉时忽略 */ }
+ },
+ },
+}
diff --git a/subPackages/sub_business_shared/components/DrawerPageContainer.vue b/subPackages/sub_business_shared/components/DrawerPageContainer.vue
index 0f23d68..1180ef5 100644
--- a/subPackages/sub_business_shared/components/DrawerPageContainer.vue
+++ b/subPackages/sub_business_shared/components/DrawerPageContainer.vue
@@ -1,11 +1,13 @@
+
{
+ this.pageGuard = false
+ this.releaseTimer = null
+ }, 350)
+ },
+ clearReleaseTimer() {
+ if (this.releaseTimer) {
+ clearTimeout(this.releaseTimer)
+ this.releaseTimer = null
+ }
+ },
close() {
this.show = false
this.$emit('close')
diff --git a/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue b/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue
index 12ddd5e..e456810 100644
--- a/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue
+++ b/subPackages/sub_business_shared/order/components/PrescriptionDetailPopup.vue
@@ -137,7 +137,7 @@
发药人
-
+
@@ -147,7 +147,7 @@
调配人
-
+
@@ -223,6 +223,8 @@ export default {
|| (w.data.pharmacist_info && w.data.pharmacist_info.identity && w.data.pharmacist_info.identity.sign_image)
|| (w.data.pharmacistInfo && w.data.pharmacistInfo.identity && w.data.pharmacistInfo.identity.sign_image)
|| ''
+ mapped.dispenserSignImage = w.data.dispenser_sign_image || ''
+ mapped.senderSignImage = w.data.sender_sign_image || ''
mapped.validHours = w.data.valid_hours || 72
mapped.status = w.data.status
mapped.patientMobile = w.data.patient ? w.data.patient.mobile : ''
diff --git a/subPackages/sub_business_shared/reconciliation/index.vue b/subPackages/sub_business_shared/reconciliation/index.vue
index dd42400..b1e2e1d 100644
--- a/subPackages/sub_business_shared/reconciliation/index.vue
+++ b/subPackages/sub_business_shared/reconciliation/index.vue
@@ -234,9 +234,10 @@ import {
} from '@/subPackages/sub_business_shared/common/filterCache.js'
import businessMixin from '@/subPackages/sub_business_shared/common/businessMixin.js'
+import pullRefreshMixin from '@/subPackages/sub_business_shared/common/pullRefreshMixin.js'
export default {
- mixins: [businessMixin],
+ mixins: [businessMixin, pullRefreshMixin],
components: { BusinessPageLayout, PageStickyHeader, CollapsibleFilterPanel },
data() {
return {
diff --git a/subPackages/sub_business_shared/user-patient/index.vue b/subPackages/sub_business_shared/user-patient/index.vue
index 6c848b8..6acc38a 100644
--- a/subPackages/sub_business_shared/user-patient/index.vue
+++ b/subPackages/sub_business_shared/user-patient/index.vue
@@ -47,8 +47,10 @@
*/
import BusinessPageLayout from '@/subPackages/sub_business_shared/components/business-page-layout.vue';
import { getWxUserList, pickProfileItems } from '@/api/userPatientProfile.js';
+import pullRefreshMixin from '@/subPackages/sub_business_shared/common/pullRefreshMixin.js';
export default {
+ mixins: [pullRefreshMixin],
components: { BusinessPageLayout },
data() {
return {
diff --git a/subPackages/sub_business_shared/user-patient/patients.vue b/subPackages/sub_business_shared/user-patient/patients.vue
index dbc57ae..6a7f46d 100644
--- a/subPackages/sub_business_shared/user-patient/patients.vue
+++ b/subPackages/sub_business_shared/user-patient/patients.vue
@@ -39,8 +39,10 @@
*/
import BusinessPageLayout from '@/subPackages/sub_business_shared/components/business-page-layout.vue';
import { getPatientListByUser, pickProfileItems } from '@/api/userPatientProfile.js';
+import pullRefreshMixin from '@/subPackages/sub_business_shared/common/pullRefreshMixin.js';
export default {
+ mixins: [pullRefreshMixin],
components: { BusinessPageLayout },
data() {
return {
diff --git a/subPackages/sub_business_shared/warehouse/detail.vue b/subPackages/sub_business_shared/warehouse/detail.vue
index 5ca993e..0249d5c 100644
--- a/subPackages/sub_business_shared/warehouse/detail.vue
+++ b/subPackages/sub_business_shared/warehouse/detail.vue
@@ -43,8 +43,13 @@
-
- {{ isPlatformWarehouse ? '修改价格' : '修改售价' }}
+
+ {{ priceLocked ? '不可改价' : (isPlatformWarehouse ? '修改价格' : '修改售价') }}
-
- 改价
+
+ {{ item._priceLocked ? '不可改价' : '改价' }}
{{ rowDisplay(item).isOnShelf ? '下架' : '上架' }}
@@ -70,9 +75,10 @@ import { withWxKey } from '@/utils/wxListKey.js'
import { mapWarehouseRow } from '@/subPackages/sub_business_shared/common/display.js'
import businessMixin from '@/subPackages/sub_business_shared/common/businessMixin.js'
+import pullRefreshMixin from '@/subPackages/sub_business_shared/common/pullRefreshMixin.js'
export default {
- mixins: [businessMixin],
+ mixins: [businessMixin, pullRefreshMixin],
components: { BusinessPageLayout, PriceEditModal },
data() {
return {
@@ -116,6 +122,11 @@ export default {
}
this.bizApi.getWarehouseList(params).then(w => {
const items = withWxKey((w.data && w.data.items) || [], 'id', 'wh')
+ // 门店仓绑定配送仓不可改价;平台仓不受此限
+ const lockPrice = this.bizCap.warehouseType !== 'platform'
+ items.forEach((it) => {
+ it._priceLocked = lockPrice && Number(it.has_delivery_warehouse) === 1
+ })
this.list = append ? this.list.concat(items) : items
this.page = page
}).finally(() => { this.loading = false })
@@ -123,7 +134,14 @@ export default {
goDetail(item) {
uni.navigateTo({ url: `${this.bizRoot}/warehouse/detail?id=${item.id}` })
},
+ /**
+ * 打开改价;门店仓绑定配送仓的商品不可改价
+ */
openPriceEdit(item) {
+ if (item && item._priceLocked) {
+ uni.showToast({ title: '该商品不可改价', icon: 'none' })
+ return
+ }
this.priceEditItem = item
this.priceModalVisible = true
},
@@ -327,6 +345,12 @@ $danger-color-light: rgba(255, 107, 107, 0.1);
border: 1rpx solid $border-color;
}
+.action-btn.btn-disabled {
+ color: $text-light;
+ background: $bg-color;
+ border-color: $border-color;
+}
+
.action-btn.btn-primary {
color: #ffffff;
background: $theme-color;
diff --git a/subPackages/sub_business_shared/withdrawal/account-change/index.vue b/subPackages/sub_business_shared/withdrawal/account-change/index.vue
index c2ce81d..1515961 100644
--- a/subPackages/sub_business_shared/withdrawal/account-change/index.vue
+++ b/subPackages/sub_business_shared/withdrawal/account-change/index.vue
@@ -45,9 +45,10 @@
diff --git a/subPackages/sub_platform_admin/store-input/audit/index.vue b/subPackages/sub_platform_admin/store-input/audit/index.vue
index 966117e..e54b037 100644
--- a/subPackages/sub_platform_admin/store-input/audit/index.vue
+++ b/subPackages/sub_platform_admin/store-input/audit/index.vue
@@ -10,9 +10,17 @@
\ No newline at end of file
diff --git a/subPackages/sub_salesperson/store-input/index.vue b/subPackages/sub_salesperson/store-input/index.vue
index 6def9d4..cfaf689 100644
--- a/subPackages/sub_salesperson/store-input/index.vue
+++ b/subPackages/sub_salesperson/store-input/index.vue
@@ -11,9 +11,17 @@
@@ -192,41 +230,40 @@
}
\ No newline at end of file
+
diff --git a/subPackages/sub_workbench/workbench_infoPatient.vue b/subPackages/sub_workbench/workbench_infoPatient.vue
index 12cb0a6..763a4db 100644
--- a/subPackages/sub_workbench/workbench_infoPatient.vue
+++ b/subPackages/sub_workbench/workbench_infoPatient.vue
@@ -219,6 +219,8 @@
撤回
+
+ 代付码
复用
查看处方
@@ -282,6 +284,9 @@
+
+
+
@@ -320,6 +325,7 @@ import {
VIP_FEATURE,
} from '@/utils/vip.js'
import VipGate from '@/components/vip-gate/vip-gate.vue'
+import ProxyPayQrcodeModal from '@/components/proxy-pay-qrcode-modal/proxy-pay-qrcode-modal.vue'
function emptyHealthInquiry() {
return {
@@ -372,6 +378,7 @@ function normalizeRegisterDetail(raw) {
export default {
components: {
VipGate,
+ ProxyPayQrcodeModal,
},
data() {
return {
@@ -401,6 +408,10 @@ export default {
rxLoadingMore: false,
/** 履约诊所 VIP permissions(全局判断用) */
storeVipPermissions: [],
+ /** 患者代付码弹窗显隐 */
+ proxyPayShow: false,
+ /** 代付码目标订单ID(处方关联的待支付商品订单) */
+ proxyPayOrderId: 0,
};
},
computed: {
@@ -453,6 +464,18 @@ export default {
payTextByIsPay(isPay) {
return Number(isPay) === 1 ? '已支付' : '未支付'
},
+ /**
+ * 打开患者代付码弹窗:出示小程序码给患者扫码支付本单
+ * 弹窗打开时组件内部按最新订单状态请求出码(已支付/已取消会被后端拦截并提示)
+ */
+ openProxyPayQrcode(item) {
+ if (!item || !item.order_id) {
+ uni.showToast({ title: '该处方暂无待支付订单', icon: 'none' })
+ return
+ }
+ this.proxyPayOrderId = item.order_id
+ this.proxyPayShow = true
+ },
apiOk(res) {
return res && (res.code === 0 || res.errcode === 0)
},
diff --git a/utils/loginSession.js b/utils/loginSession.js
index 0bf05fb..dddfb7f 100644
--- a/utils/loginSession.js
+++ b/utils/loginSession.js
@@ -80,11 +80,16 @@ export function resolveLoggedInTarget() {
export function redirectIfLoggedIn() {
const target = resolveLoggedInTarget();
- if (target && target.url) {
- uni.reLaunch({ url: target.url });
- return true;
- }
- return false;
+ if (!target || !target.url) return false;
+ // 启动尚未挂上页面时不要 reLaunch,否则微信会报 appLaunch with non-empty page stack
+ const pages = getCurrentPages();
+ if (!pages || !pages.length) return false;
+ const cur = pages[pages.length - 1];
+ const curPath = cur && cur.route ? '/' + cur.route : '';
+ const targetPath = String(target.url).split('?')[0];
+ if (curPath === targetPath) return true;
+ uni.reLaunch({ url: target.url });
+ return true;
}
export function saveLoginSession(result) {