Compare commits

..
25 Commits
Author SHA1 Message Date
Your Name 0c1709d589 Merge branch 'master' into yeji-5-11 2026-05-12 10:43:04 +08:00
Your Name a3892001d3 更新 2026-05-12 10:42:14 +08:00
Your Name 7add364e20 更新 2026-05-11 17:48:47 +08:00
Your Name 0ebea74fde 更新 2026-05-11 17:46:29 +08:00
Your Name 1156787327 更新 2026-05-11 16:34:44 +08:00
Your Name 15cf6324f6 更新 2026-05-11 16:10:06 +08:00
long 1338b8735c Merge branch '20260511-long' 2026-05-11 15:06:07 +08:00
long 82f229adf2 Update 2026_05_11_diagnosis_assign_read.sql 2026-05-11 15:06:01 +08:00
long 048e43a662 Merge branch '20260511-long' 2026-05-11 15:04:33 +08:00
long d8d4da197e 新指派医助提示 2026-05-11 15:04:24 +08:00
gr a0325a8fb1 更新 2026-05-11 12:35:46 +08:00
Your Name 091db50841 更新 2026-05-11 12:32:25 +08:00
long 1774a87dd7 update 2026-05-11 11:41:42 +08:00
Your Name 62d15efbaf 更新 2026-05-11 11:36:26 +08:00
long c468c57cda 关联支付单豁免 2026-05-11 11:25:03 +08:00
Your Name bacdd6386f 新增 2026-05-09 18:36:46 +08:00
long ea290c4c7b Merge branch 'long-0509' 2026-05-09 18:32:23 +08:00
long 31b4afdcb7 Update PrescriptionLogic.php 2026-05-09 18:32:16 +08:00
long 379d2ef404 Merge branch 'master' of https://gitee.com/v_cms/zyt 2026-05-09 18:07:38 +08:00
long 5cdb7ebb9e Merge branch 'long-0509' 2026-05-09 18:07:37 +08:00
long 496a2b870b 业务订单优化 2026-05-09 18:07:30 +08:00
Your Name 471bdf12b7 更新 2026-05-09 17:45:04 +08:00
long 8fe4683e64 Revert "1"
This reverts commit 0a37335f3c.
2026-05-09 17:35:33 +08:00
long c34409edde Merge branch 'long-0509' 2026-05-09 17:14:13 +08:00
long 0a37335f3c 1 2026-05-09 17:14:03 +08:00
413 changed files with 5406 additions and 822 deletions
+3
View File
@@ -30,3 +30,6 @@ bin-release/
/.claude
/.claude
/.kbctx
/server/.spool
/server/.claude
/.spool
+5
View File
@@ -104,3 +104,8 @@ export function orderActionLogStats(params?: { start_time?: string; end_time?: s
export function orderBatchAssignAssistant(params: { order_ids: number[]; assistant_id: number }) {
return request.post({ url: '/order.order/assignAssistant', params })
}
/** 设置/取消支付单豁免权 */
export function orderSetExempt(params: { id: number; is_exempt: 0 | 1 }) {
return request.post({ url: '/order.order/setExempt', params })
}
+57
View File
@@ -103,3 +103,60 @@ export function doctorDailyStatsOverview(params: {
}) {
return request.get({ url: '/stats.doctorDailyStats/overview', params })
}
/** 提成结算接口计算较重,单独放宽超时(默认多为 60s) */
const COMMISSION_SETTLEMENT_TIMEOUT_MS = 120000
/** 提成结算业绩(独立于业绩看板 yejiStats) */
export function commissionSettlementOverview(params: {
settlement_month: string
dept_ids?: number[] | string
channel_code?: string
}) {
return request.get(
{ url: '/stats.commissionSettlement/overview', params, timeout: COMMISSION_SETTLEMENT_TIMEOUT_MS },
{ ignoreCancelToken: true }
)
}
export function commissionSettlementDeptOptions() {
return request.get({ url: '/stats.commissionSettlement/deptOptions' })
}
export function commissionSettlementChannelOptions() {
return request.get({ url: '/stats.commissionSettlement/channelOptions' })
}
/** 提成核对:订单明细分页 bucket: 空|current|deferred */
export function commissionSettlementOrderLines(params: {
settlement_month: string
dept_ids?: number[] | string
channel_code?: string
page?: number
page_size?: number
bucket?: string
}) {
return request.get(
{ url: '/stats.commissionSettlement/orderLines', params, timeout: COMMISSION_SETTLEMENT_TIMEOUT_MS },
{ ignoreCancelToken: true }
)
}
export function commissionSettlementConfirmStatus(params: {
settlement_month: string
dept_ids?: number[] | string
channel_code?: string
}) {
return request.get({ url: '/stats.commissionSettlement/confirmStatus', params })
}
export function commissionSettlementSaveReconcile(params: Record<string, any>) {
return request.post({ url: '/stats.commissionSettlement/saveReconcile', params })
}
export function commissionSettlementConfirmFinalize(params: Record<string, any>) {
return request.post(
{ url: '/stats.commissionSettlement/confirmFinalize', params, timeout: COMMISSION_SETTLEMENT_TIMEOUT_MS },
{ ignoreCancelToken: true }
)
}
@@ -911,11 +911,12 @@
<span class="text-red-500">¥{{ row.amount }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="82" align="center">
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="payOrderStatusTag(row.status)" size="small">
{{ row.status_desc || orderStatusText(row.status) }}
</el-tag>
<el-tag v-if="row.is_exempt === 1" type="warning" size="small" class="ml-1">豁免</el-tag>
</template>
</el-table-column>
<el-table-column prop="creator_name" label="创建人" width="80" show-overflow-tooltip />
@@ -968,11 +969,12 @@
<span class="text-red-500">¥{{ row.amount }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="82" align="center">
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="payOrderStatusTag(row.status)" size="small">
{{ row.status_desc || orderStatusText(row.status) }}
</el-tag>
<el-tag v-if="row.is_exempt === 1" type="warning" size="small" class="ml-1">豁免</el-tag>
</template>
</el-table-column>
<el-table-column prop="creator_name" label="创建人" width="80" show-overflow-tooltip />
@@ -925,11 +925,12 @@
<span class="text-red-500">¥{{ row.amount }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="82" align="center">
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="payOrderStatusTag(row.status)" size="small">
{{ row.status_desc || orderStatusText(row.status) }}
</el-tag>
<el-tag v-if="row.is_exempt === 1" type="warning" size="small" class="ml-1">豁免</el-tag>
</template>
</el-table-column>
<el-table-column prop="creator_name" label="创建人" width="80" show-overflow-tooltip />
@@ -982,11 +983,12 @@
<span class="text-red-500">¥{{ row.amount }}</span>
</template>
</el-table-column>
<el-table-column label="状态" width="82" align="center">
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="payOrderStatusTag(row.status)" size="small">
{{ row.status_desc || orderStatusText(row.status) }}
</el-tag>
<el-tag v-if="row.is_exempt === 1" type="warning" size="small" class="ml-1">豁免</el-tag>
</template>
</el-table-column>
<el-table-column prop="creator_name" label="创建人" width="80" show-overflow-tooltip />
File diff suppressed because it is too large Load Diff
+419 -227
View File
@@ -290,12 +290,12 @@
</table>
</div>
<div class="yeji-table__foot yeji-table__foot--left">
<span>诊金单位 · 被指派数与部门业绩表同口径 · 接诊率 = 诊金 ÷ 进线/进线</span>
<span>诊金单位 · 诊金/接诊诊单/复诊均按订单创建人 = 该医助归属与部门合计业绩 / 接诊诊单 / 复诊同口径 · 被指派数与部门业绩表同口径 · 接诊率 = 诊金 ÷ 进线/进线</span>
<span v-if="lb.er_center_subtree">
· 复诊列为二中心口径同一诊单业务单序列第 2 笔起点击数字查看对应业务订单
</span>
<span>
· 预约诊单预约日期在统计区间内状态含已预约/已完成/已过号不含已取消医助归属与接诊单数一致各科组展示全部医助
· 预约诊单预约日期在统计区间内状态含已预约/已完成/已过号不含已取消医助归属与接诊单数一致按挂号 assistant_id 优先否则诊单 assistant_id各科组展示全部医助
</span>
</div>
</div>
@@ -317,75 +317,7 @@
</el-tab-pane>
<el-tab-pane label="甄养堂互联网医院诊金" name="zyyt" lazy>
<p class="yeji-zyyt-intro">
各中心部门诊金业绩进线与 ROI 与顶部渠道展示部门日期筛选联动本月 / 本周 / 今日等多张业绩表中预约诊单列数字可点开查看每条挂号记录
</p>
<!-- <el-alert
v-if="channelFilterNote"
:title="channelFilterNote"
type="info"
show-icon
:closable="false"
class="filter-alert"
/> -->
<!-- 目标进度卡片 -->
<div
v-if="targetProgressCard || targetProgressLoading"
v-loading="targetProgressLoading"
class="tp-wrap"
>
<div v-if="targetProgressCard" class="tp-card">
<div class="tp-card__title">{{ targetProgressCard.title }}</div>
<div class="tp-card__body">
<div
v-for="sec in targetProgressCard.sections"
:key="sec.dept_id"
class="tp-section"
>
<div class="tp-section__head">
<div class="tp-section__title-col">
<span v-if="sec.parent_dept_name" class="tp-section__parent">{{
sec.parent_dept_name
}}</span>
<span class="tp-section__name">{{ sec.dept_name }}目标</span>
</div>
<span class="tp-section__target">{{ formatMoneyW(sec.target_amount) }}</span>
</div>
<table class="tp-table">
<tbody>
<tr>
<td class="tp-lbl">昨日诊金</td>
<td class="tp-val">{{ formatInt(sec.yesterday_amount) }}</td>
</tr>
<tr v-if="sec.douyin_amount !== null">
<td class="tp-lbl">抖音总诊金</td>
<td class="tp-val">{{ formatInt(sec.douyin_amount) }}</td>
</tr>
<tr v-if="sec.tuifen_amount !== null">
<td class="tp-lbl">推粉总诊金</td>
<td class="tp-val">{{ formatInt(sec.tuifen_amount) }}</td>
</tr>
<tr>
<td class="tp-lbl">总诊金</td>
<td class="tp-val tp-val--total">{{ formatInt(sec.total_amount) }}</td>
</tr>
<tr>
<td class="tp-lbl">目标进度</td>
<td class="tp-val">{{ formatMoney(sec.target_progress) }}</td>
</tr>
<tr>
<td class="tp-lbl">完成进度</td>
<td class="tp-val" :class="achievementClass(sec.completion_rate)">{{ formatAchievement(sec.completion_rate) }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 业绩表4 /N -->
<!-- 业绩表4 /N 目标看板见目标看板卡片Tab -->
<div v-loading="loading" class="tables-wrap">
<div v-if="!loading && tables.length === 0" class="empty-tip">
<el-empty description="暂无数据" />
@@ -438,7 +370,7 @@
<el-tooltip placement="top" effect="dark" :show-after="200">
<template #content>
<div style="max-width: 320px; line-height: 1.7; font-size: 12px">
<b>名称含二中心</b>的部门及其组织下级与本表区间一致按患者业务单 <b>create_time</b> 排序<b> 1 笔不计</b> 2 笔起计入合计分列复诊2复诊三含本部门及下级汇总订单条件同合计业绩非取消非二中心子树部门为 0
<b>名称含二中心</b>的部门及其组织下级候选订单为有诊单医助的非取消业务单按患者 <b>create_time</b> 排序<b> 1 笔不计</b> 2 笔起计入合计分列复诊2复诊三<b>归属</b>按订单创建人的人事部门<b>合计业绩</b>列同口径非二中心子树部门为 0
</div>
</template>
<el-icon class="col-info"><InfoFilled /></el-icon>
@@ -463,8 +395,14 @@
<el-tooltip placement="top" effect="dark" :show-after="200">
<template #content>
<div style="max-width: 300px; line-height: 1.7; font-size: 12px">
按订单<b>创建时间</b>统计剔除履约已取消金额与<b>接诊诊单</b>列一致诊单<b>医助</b>或订单<b>创建人</b>的人事部门落在本展示行含下级即计入多行命中时取最深的展示部门<br />
<b>不受渠道筛选影响</b>与侧栏按部门打开的业务订单列表可对齐
<<<<<<< HEAD
按订单<b>创建时间</b>统计剔除履约已取消金额与<b>接诊诊单</b>列一致仅按<b>订单创建人</b>的人事部门落在本展示行含下级计入多行命中时取最深的展示部门<b>医助排行榜诊金</b>同口径<br />
<b>不受渠道筛选影响</b>与侧栏按部门打开的业务订单列表对齐<br />
=======
按订单<b>创建时间</b>统计剔除履约已取消金额与<b>接诊诊单</b>列一致<b>创建人</b>人事部门优先无创建人时回退诊单<b>医助</b>落在本展示行含下级即计入同表多行命中时取最深的展示部门<br />
<b>不受渠道筛选影响</b>与侧栏按部门打开的业务订单列表可对齐<br />
>>>>>>> master
点击金额可查看对应业务订单明细侧栏默认合计业绩全量列表
</div>
</template>
<el-icon class="col-info"><InfoFilled /></el-icon>
@@ -477,7 +415,8 @@
<div style="max-width: 340px; line-height: 1.7; font-size: 12px">
{{ tb.channel_name }}渠道业绩与卡片标题渠道一致处方订单列表业绩<b>同口径</b>按订单
<b>create_time</b> 归日剔除履约已取消(4)<br />
渠道判定用 EXISTS该患者有任一挂号 <b>channels 命中字典 + status=3</b>不限挂号时点
渠道判定用 EXISTS该患者有任一挂号 <b>channels 命中字典 + status=3</b>不限挂号时点<br />
点击金额可查看该部门本渠道订单明细侧栏渠道筛选列表
</div>
</template>
<el-icon class="col-info" aria-label="说明"><InfoFilled /></el-icon>
@@ -511,8 +450,12 @@
<el-tooltip placement="top" effect="dark" :show-after="200">
<template #content>
<div style="max-width: 320px; line-height: 1.7; font-size: 12px">
<<<<<<< HEAD
<b>业务订单条数</b>非取消订单 <b>create_time</b> 落入区间<b>fulfillment_status 4</b><b>订单创建人</b>的人事部门落在该部门子树即计入表格多行命中时取最深的展示部门<b>合计业绩 / 医助排行榜接诊诊单</b>同口径选定渠道时本列仍为全量
=======
<b>业务订单条数</b>非取消订单 <b>create_time</b> 落入区间<b>fulfillment_status 4</b>与列表筛选
<b>assistant_dept_id</b> 时一致诊单 <b>医助</b>或订 <b>创建人</b>的人事部门落在该部门子树即计入表格多行命中时取最深的展示部门与侧栏勾选与表格业绩对齐时的集合可能略有差异选定渠道时本列仍为全量
<b>assistant_dept_id</b> 时一致<b>创建人</b>人事部门优先无创建人则诊 <b>医助</b>落在该部门子树即计入表格多行命中时取最深的展示部门与侧栏勾选与表格业绩对齐时的集合可能略有差异选定渠道时本列仍为全量
>>>>>>> master
</div>
</template>
<el-icon class="col-info"><InfoFilled /></el-icon>
@@ -611,8 +554,25 @@
>{{ formatInt(yejiRevisitSlotAt(r, slot)) }}</span>
<template v-else>{{ formatInt(yejiRevisitSlotAt(r, slot)) }}</template>
</td>
<td>{{ formatMoney(r.performance_amount) }}</td>
<td v-if="tb.channel_name" class="col-completed">{{ formatMoney(r.completed_performance_amount) }}</td>
<td>
<span
v-if="yejiPerfCellDrawerEligible(tb, r, 'total')"
class="yeji-lead-cell--link"
@click.stop="onYejiPerformanceCellClick(tb, r, 'total')"
>{{ formatMoney(r.performance_amount) }}</span>
<template v-else>{{ formatMoney(r.performance_amount) }}</template>
</td>
<td
v-if="tb.channel_name"
class="col-completed"
>
<span
v-if="yejiPerfCellDrawerEligible(tb, r, 'channel')"
class="yeji-lead-cell--link"
@click.stop="onYejiPerformanceCellClick(tb, r, 'channel')"
>{{ formatMoney(r.completed_performance_amount) }}</span>
<template v-else>{{ formatMoney(r.completed_performance_amount) }}</template>
</td>
<td @click.stop="onYejiDeptAppointmentBookedClick(tb, r)">
<span
v-if="
@@ -639,8 +599,25 @@
v-for="slot in yejiRevisitSlotColumns"
:key="'yjvt-' + idx + '-' + slot"
>{{ formatInt(yejiRevisitSlotAt(tb.total, slot)) }}</td>
<td>{{ formatMoney(tb.total.performance_amount) }}</td>
<td v-if="tb.channel_name" class="col-completed">{{ formatMoney(tb.total.completed_performance_amount) }}</td>
<td>
<span
v-if="yejiPerfTotalRowDrawerEligible(tb, 'total')"
class="yeji-lead-cell--link"
@click.stop="onYejiPerformanceTotalRowClick(tb, 'total')"
>{{ formatMoney(tb.total.performance_amount) }}</span>
<template v-else>{{ formatMoney(tb.total.performance_amount) }}</template>
</td>
<td
v-if="tb.channel_name"
class="col-completed"
>
<span
v-if="yejiPerfTotalRowDrawerEligible(tb, 'channel')"
class="yeji-lead-cell--link"
@click.stop="onYejiPerformanceTotalRowClick(tb, 'channel')"
>{{ formatMoney(tb.total.completed_performance_amount) }}</span>
<template v-else>{{ formatMoney(tb.total.completed_performance_amount) }}</template>
</td>
<td>{{ formatInt(tb.total.appointment_booked_count ?? 0) }}</td>
<td>{{ formatInt(tb.total.consult_count) }}</td>
<td>{{ formatInt(tb.total.deal_order_count) }}</td>
@@ -663,6 +640,72 @@
</div>
</el-tab-pane>
<el-tab-pane label="目标看板(卡片)" name="zyyt_matrix" lazy>
<div v-loading="targetProgressLoading" class="tp-matrix-wrap">
<template v-if="targetProgressCard">
<h2 class="tp-matrix__title">{{ targetProgressCard.title }}</h2>
<div class="tp-matrix" role="list">
<div
v-for="sec in targetProgressCard.sections"
:key="'tm-' + sec.dept_id"
class="tp-matrix-card"
role="listitem"
>
<div class="tp-matrix-card__head">
<div class="tp-matrix-card__titles">
<span v-if="sec.parent_dept_name" class="tp-matrix-card__parent">{{
sec.parent_dept_name
}}</span>
<span class="tp-matrix-card__name">{{ sec.dept_name }}目标</span>
</div>
<span class="tp-matrix-card__target">{{ formatMoneyW(sec.target_amount) }}</span>
</div>
<table class="tp-matrix-card__table">
<tbody>
<tr>
<td class="tp-matrix-card__lbl">昨日诊金</td>
<td class="tp-matrix-card__num">{{ formatInt(sec.yesterday_amount) }}</td>
</tr>
<tr v-if="sec.douyin_amount !== null">
<td class="tp-matrix-card__lbl">抖音总诊金</td>
<td class="tp-matrix-card__num">{{ formatInt(sec.douyin_amount) }}</td>
</tr>
<tr v-if="sec.tuifen_amount !== null">
<td class="tp-matrix-card__lbl">推粉总诊金</td>
<td class="tp-matrix-card__num">{{ formatInt(sec.tuifen_amount) }}</td>
</tr>
<tr>
<td class="tp-matrix-card__lbl">总诊金</td>
<td class="tp-matrix-card__num tp-matrix-card__num--hot">
{{ formatInt(sec.total_amount) }}
</td>
</tr>
<tr>
<td class="tp-matrix-card__lbl">目标进度</td>
<td class="tp-matrix-card__num">{{ formatMoney(sec.target_progress) }}</td>
</tr>
<tr>
<td class="tp-matrix-card__lbl">完成进度</td>
<td
class="tp-matrix-card__num tp-matrix-card__num--hot"
:class="achievementClass(sec.completion_rate)"
>
{{ formatAchievement(sec.completion_rate) }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<el-empty
v-else-if="!targetProgressLoading"
class="tp-matrix-empty"
description="暂无目标数据,请先配置当月部门目标或为部门设置诊金目标后刷新页面"
/>
</div>
</el-tab-pane>
</el-tabs>
</el-card>
@@ -1047,6 +1090,7 @@
</template>
</el-table-column>
<el-table-column prop="doctor_name" label="开方人" width="88" show-overflow-tooltip />
<el-table-column prop="assistant_name" label="诊单医助" width="88" show-overflow-tooltip />
<el-table-column prop="creator_name" label="创建人" width="88" show-overflow-tooltip />
</el-table>
<el-empty v-if="!orderDrawerLoading && orderDrawerLists.length === 0" description="暂无业务订单" />
@@ -1623,7 +1667,7 @@ const appointmentLinesShowChannelColumn = computed(() =>
)
/** 图表 / 数据表切换 */
const yejiDisplayTab = ref<'doctor' | 'leaderboard' | 'zyyt'>('zyyt')
const yejiDisplayTab = ref<'doctor' | 'leaderboard' | 'zyyt' | 'zyyt_matrix'>('zyyt')
/** 与菜单 stats.doctorDailyStats/overview 一致;无权限则不展示医生统计表/图、不请求接口 */
const userStore = useUserStore()
@@ -2069,7 +2113,15 @@ const orderDrawerSplitPerfCache = ref<{
} | null>(null)
type OrderDrawerFilter =
| { mode: 'dept'; deptId: number; deptName: string; start: string; end: string }
| {
mode: 'dept'
deptId: number
deptName: string
start: string
end: string
/** 当前业绩表各展示行 dept_id,用于侧栏与「接诊诊单」列对齐(创建人优先 + 最深展示行) */
yejiTableRowDeptIds?: number[]
}
| {
mode: 'assistant'
assistantId: number
@@ -2586,40 +2638,90 @@ function formatOrderDrawerTime(t: unknown): string {
return s.length >= 16 ? s.slice(0, 16) : s
}
async function fetchOrderDrawerPage() {
/** 业务订单侧栏列表筛选(不含分页) */
function buildOrderDrawerListParams(): Record<string, any> | null {
const f = orderDrawerFilter.value
if (!f) return
if (!f) return null
const params: Record<string, any> = {
start_time: `${f.start} 00:00:00`,
end_time: `${f.end} 23:59:59`,
/** 与业绩列口径一致:不列出履约已取消(4) */
exclude_fulfillment_cancelled: 1,
/**
* 业绩看板入口标志:后端 PrescriptionOrderLists::applyDoctorAssistantFilters 看到此标志后,
* assistant_id / assistant_dept_id 一律按订单创建人收窄(与表格诊金/合计业绩/复诊同口径),
* 而非默认的「创建人 ∪ 诊单医助」并集。同时启用 extend 字段(约诊数、合计业绩对照)。
*/
yeji_order_drawer: 1,
}
if (f.mode === 'dept') {
params.assistant_dept_id = f.deptId
<<<<<<< HEAD
=======
/** 与 YejiStatsLogic 最深展示行 + 创建人优先归属一致 */
if (f.yejiTableRowDeptIds && f.yejiTableRowDeptIds.length > 0) {
params.yeji_table_row_dept_ids = f.yejiTableRowDeptIds.join(',')
}
/** 勿传 yeji_drawer_match_table_performance:该参数按「业绩归因」医助收窄,与看板列表摊行不一致 */
>>>>>>> master
if (selectedDeptIds.value.length > 0) {
params.dept_ids = selectedDeptIds.value.join(',')
}
} else {
params.assistant_id = f.assistantId
if (f.erCenterRevisitSlot !== undefined) {
params.yeji_er_center_revisit_only = 1
params.yeji_er_center_revisit_slot = f.erCenterRevisitSlot
}
}
if (
selectedChannel.value &&
orderDrawerVisible.value &&
orderDrawerListTab.value === 'channel'
) {
params.channel_code = selectedChannel.value
}
return params
}
async function hydrateOrderDrawerSplitPerfCache() {
const base = buildOrderDrawerListParams()
if (!base || !selectedChannel.value) return
const params: Record<string, any> = {
...base,
channel_code: selectedChannel.value,
page_no: 1,
page_size: 1,
}
try {
const res: any = await prescriptionOrderLists(params)
const ex = res?.extend && typeof res.extend === 'object' ? res.extend : null
if (ex && ex.stats_yeji_drawer_total_performance_amount != null) {
orderDrawerSplitPerfCache.value = {
totalAmount: Number(ex.stats_yeji_drawer_total_performance_amount),
totalOrderCount: Number(ex.stats_yeji_drawer_total_performance_order_count ?? 0),
channelAmount: Number(ex.stats_order_amount_performance ?? 0),
channelOrderCount: Number(res?.count ?? 0),
}
}
} catch {
// 对照指标失败不打断列表
}
}
async function fetchOrderDrawerPage() {
const base = buildOrderDrawerListParams()
if (!base) return
if (selectedChannel.value && orderDrawerListTab.value === 'total') {
orderDrawerSplitPerfCache.value = null
}
orderDrawerLoading.value = true
try {
const params: Record<string, any> = {
...base,
page_no: orderDrawerPage.value,
page_size: orderDrawerPageSize.value,
start_time: `${f.start} 00:00:00`,
end_time: `${f.end} 23:59:59`,
/** 与业绩列口径一致:不列出履约已取消(4) */
exclude_fulfillment_cancelled: 1,
/** 侧栏展示约诊数等 extend 字段 */
yeji_order_drawer: 1,
}
if (f.mode === 'dept') {
params.assistant_dept_id = f.deptId
/** 与看板「接诊诊单」列一致:处方列表默认 assistant_dept_id(诊单医助或创建人∪子树),不用业绩摊行医助集合 */
if (selectedDeptIds.value.length > 0) {
params.dept_ids = selectedDeptIds.value.join(',')
}
} else {
params.assistant_id = f.assistantId
if (f.erCenterRevisitSlot !== undefined) {
params.yeji_er_center_revisit_only = 1
params.yeji_er_center_revisit_slot = f.erCenterRevisitSlot
}
}
if (
selectedChannel.value &&
orderDrawerChannelSplitActive.value &&
orderDrawerListTab.value === 'channel'
) {
params.channel_code = selectedChannel.value
}
const res: any = await prescriptionOrderLists(params)
orderDrawerLists.value = Array.isArray(res?.lists) ? res.lists : []
@@ -2640,6 +2742,13 @@ async function fetchOrderDrawerPage() {
channelOrderCount: Number(res?.count ?? 0),
}
}
if (
selectedChannel.value &&
orderDrawerVisible.value &&
orderDrawerListTab.value === 'total'
) {
await hydrateOrderDrawerSplitPerfCache()
}
} catch (e: any) {
ElMessage.error(e?.msg || e?.message || '加载业务订单失败')
orderDrawerLists.value = []
@@ -2650,8 +2759,9 @@ async function fetchOrderDrawerPage() {
}
}
function openOrderDrawerByDept(tb: YejiTable, row: YejiRow) {
orderDrawerListTab.value = 'channel'
function openOrderDrawerByDept(tb: YejiTable, row: YejiRow, opts?: { listTab?: 'total' | 'channel' }) {
const channelSplit = Boolean(selectedChannel.value && tb.channel_name)
orderDrawerListTab.value = channelSplit ? opts?.listTab ?? 'channel' : 'channel'
orderDrawerSplitPerfCache.value = null
orderDrawerFilter.value = {
mode: 'dept',
@@ -2659,14 +2769,83 @@ function openOrderDrawerByDept(tb: YejiTable, row: YejiRow) {
deptName: row.dept_name,
start: tb.start_date,
end: tb.end_date,
yejiTableRowDeptIds: tb.rows.map(r => r.dept_id).filter((id): id is number => typeof id === 'number' && id > 0),
}
orderDrawerTitle.value = `业务订单 · ${row.dept_name}`
orderDrawerHint.value = `创建时间:${tb.start_date} ${tb.end_date} · 与「接诊诊单」同口径:诊单医助或订单创建人落在本部门(含下级)· 不含履约已取消`
<<<<<<< HEAD
orderDrawerHint.value = `创建时间:${tb.start_date} ${tb.end_date} · 与「合计业绩 / 接诊诊单」同口径:订单创建人人事部门 ∈ 本部门子树 · 不含履约已取消`
=======
orderDrawerHint.value = `创建时间:${tb.start_date} ${tb.end_date} · 与「接诊诊单」同口径:**创建人**人事部门优先,无创建人则诊单医助;同表多行间取最深归属 · 不含履约已取消`
>>>>>>> master
orderDrawerPage.value = 1
orderDrawerVisible.value = true
void fetchOrderDrawerPage()
}
/** 顶部「展示部门」仅选中 1 个根节点时:合计行业绩对应该子树下的订单汇总 */
function openOrderDrawerByYejiTableScope(
tb: YejiTable,
rootDeptId: number,
listTab: 'total' | 'channel'
) {
const channelSplit = Boolean(selectedChannel.value && tb.channel_name)
orderDrawerListTab.value = channelSplit ? listTab : 'channel'
orderDrawerSplitPerfCache.value = null
orderDrawerFilter.value = {
mode: 'dept',
deptId: rootDeptId,
deptName: '当前展示合计',
start: tb.start_date,
end: tb.end_date,
yejiTableRowDeptIds: tb.rows.map(r => r.dept_id).filter((id): id is number => typeof id === 'number' && id > 0),
}
orderDrawerTitle.value = '业务订单 · 当前展示合计'
orderDrawerHint.value = `创建时间:${tb.start_date} ${tb.end_date} · 已选展示部门 1 个根节点(含其下全部展示行)· 不含履约已取消`
orderDrawerPage.value = 1
orderDrawerVisible.value = true
void fetchOrderDrawerPage()
}
function yejiPerfCellDrawerEligible(tb: YejiTable, row: YejiRow, kind: 'total' | 'channel'): boolean {
if (isUnassignedYejiRow(row) || row.dept_id <= 0) {
return false
}
if (kind === 'channel' && !tb.channel_name) {
return false
}
return true
}
function yejiPerfTotalRowDrawerEligible(tb: YejiTable, kind: 'total' | 'channel'): boolean {
if (selectedDeptIds.value.length !== 1) {
return false
}
if (kind === 'channel' && !tb.channel_name) {
return false
}
return true
}
function onYejiPerformanceCellClick(tb: YejiTable, row: YejiRow, kind: 'total' | 'channel') {
if (!yejiPerfCellDrawerEligible(tb, row, kind)) {
return
}
const listTab: 'total' | 'channel' = kind === 'total' ? 'total' : 'channel'
openOrderDrawerByDept(tb, row, { listTab })
}
function onYejiPerformanceTotalRowClick(tb: YejiTable, kind: 'total' | 'channel') {
if (!yejiPerfTotalRowDrawerEligible(tb, kind)) {
return
}
const rootDeptId = selectedDeptIds.value[0]
if (!rootDeptId) {
return
}
const listTab: 'total' | 'channel' = kind === 'total' ? 'total' : 'channel'
openOrderDrawerByYejiTableScope(tb, rootDeptId, listTab)
}
function openOrderDrawerByAssistant(row: LeaderboardPack['leaderboards'][0]['rows'][0], start: string, end: string) {
orderDrawerListTab.value = 'channel'
orderDrawerSplitPerfCache.value = null
@@ -2678,7 +2857,7 @@ function openOrderDrawerByAssistant(row: LeaderboardPack['leaderboards'][0]['row
end,
}
orderDrawerTitle.value = `业务订单 · ${row.name}`
orderDrawerHint.value = `创建时间:${start} ${end} · 诊单医助 · 不含履约已取消`
orderDrawerHint.value = `创建时间:${start} ${end} · 创建人=${row.name}(与排行榜诊金同口径)· 不含履约已取消`
orderDrawerPage.value = 1
orderDrawerVisible.value = true
void fetchOrderDrawerPage()
@@ -2702,7 +2881,7 @@ function openOrderDrawerByAssistantErCenterRevisit(
}
const slotLbl = revisitSlot === 0 ? '复诊合计' : yejiRevisitSlotColumnTitle(revisitSlot)
orderDrawerTitle.value = `业务订单 · ${assistant.name} · ${slotLbl}`
orderDrawerHint.value = `创建时间:${start} ${end} · 诊单医助 · 仅二中心复诊口径 · ${slotLbl} · 不含履约已取消`
orderDrawerHint.value = `创建时间:${start} ${end} · 创建人=${assistant.name}(与部门表 / 排行榜复诊同口径)· 仅二中心复诊口径 · ${slotLbl} · 不含履约已取消`
orderDrawerPage.value = 1
orderDrawerVisible.value = true
void fetchOrderDrawerPage()
@@ -3946,118 +4125,7 @@ onMounted(async () => {
}
}
/* ── 目标进度卡片 ── */
.tp-wrap {
min-height: 40px;
margin-bottom: 20px;
}
.tp-card {
display: inline-flex;
flex-direction: column;
max-width: 100%;
border-radius: var(--yj-radius);
overflow: hidden;
font-size: 13px;
background: var(--yj-surface);
border: 1px solid var(--yj-line);
box-shadow: var(--yj-shadow-md);
&__title {
background: var(--yj-surface-muted);
color: var(--yj-ink);
font-weight: 700;
font-size: 14px;
text-align: center;
padding: 14px 20px;
letter-spacing: 0.04em;
border-bottom: 1px solid var(--yj-line);
}
&__body {
display: flex;
flex-wrap: wrap;
gap: 0;
}
}
.tp-section {
min-width: 200px;
flex: 1 1 200px;
border-right: 1px solid var(--yj-line);
&:last-child {
border-right: none;
}
&__head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
background: var(--yj-brand-soft);
padding: 11px 14px;
border-bottom: 1px solid var(--yj-line);
}
&__title-col {
display: flex;
flex-direction: column;
gap: 3px;
min-width: 0;
}
&__parent {
font-size: 11px;
font-weight: 600;
color: var(--yj-muted);
line-height: 1.25;
}
&__name {
font-weight: 700;
font-size: 13px;
color: var(--yj-ink);
}
&__target {
font-size: 13px;
font-weight: 700;
color: var(--yj-accent);
}
}
.tp-table {
width: 100%;
border-collapse: collapse;
.tp-lbl {
padding: 8px 12px;
color: var(--yj-muted);
font-size: 12px;
border-bottom: 1px solid var(--yj-line);
white-space: nowrap;
}
.tp-val {
padding: 8px 14px;
font-weight: 600;
text-align: right;
border-bottom: 1px solid var(--yj-line);
white-space: nowrap;
color: var(--yj-ink);
font-variant-numeric: tabular-nums;
&--total {
color: var(--yj-accent);
}
}
tr:last-child td {
border-bottom: none;
}
}
/* 目标完成率色条:目标看板(卡片)Tab 复用 */
.tp-good {
color: #15803d !important;
font-weight: 700;
@@ -4071,6 +4139,126 @@ onMounted(async () => {
font-weight: 700;
}
/* 目标看板卡片栅格(与顶部「甄养堂」条带数据同源,8 列铺满) */
.tp-matrix-wrap {
min-height: 120px;
padding: 8px 4px 16px;
}
.tp-matrix__title {
margin: 0 0 18px;
text-align: center;
font-size: 16px;
font-weight: 700;
color: var(--yj-ink);
letter-spacing: 0.02em;
}
.tp-matrix {
display: grid;
grid-template-columns: repeat(8, minmax(0, 1fr));
gap: 12px;
align-items: stretch;
}
@media (max-width: 1600px) {
.tp-matrix {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
}
@media (max-width: 900px) {
.tp-matrix {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
.tp-matrix-card {
display: flex;
flex-direction: column;
min-width: 0;
border: 1px solid var(--yj-line);
border-radius: var(--yj-radius-sm);
background: var(--yj-surface);
box-shadow: var(--yj-shadow-sm);
font-size: 12px;
overflow: hidden;
&__head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 8px;
padding: 10px 12px;
background: var(--yj-brand-soft);
border-bottom: 1px solid var(--yj-line);
}
&__titles {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
&__parent {
font-size: 11px;
font-weight: 600;
color: var(--yj-muted);
line-height: 1.2;
}
&__name {
font-weight: 700;
font-size: 12px;
color: var(--yj-ink);
line-height: 1.35;
}
&__target {
flex-shrink: 0;
font-size: 13px;
font-weight: 700;
color: var(--yj-accent);
font-variant-numeric: tabular-nums;
}
&__table {
width: 100%;
border-collapse: collapse;
}
&__lbl {
padding: 7px 10px;
color: var(--yj-muted);
font-size: 11px;
border-bottom: 1px solid var(--yj-line);
white-space: nowrap;
}
&__num {
padding: 7px 10px;
font-weight: 600;
text-align: right;
border-bottom: 1px solid var(--yj-line);
color: var(--yj-ink);
font-variant-numeric: tabular-nums;
&--hot {
color: var(--yj-accent);
font-weight: 700;
}
}
tr:last-child td {
border-bottom: none;
}
}
.tp-matrix-empty {
padding: 32px 16px;
}
.leaderboard-sub {
font-size: 13px;
font-weight: 500;
@@ -4640,6 +4828,10 @@ tbody tr.yeji-row--action:hover .yeji-lead-cell--link {
color: color-mix(in srgb, var(--yj-brand, #2563eb) 88%, #000);
}
tbody tr.total-row:hover .yeji-lead-cell--link {
color: color-mix(in srgb, var(--yj-brand, #2563eb) 88%, #000);
}
.yeji-leadlines-dialog__pager {
margin-top: 14px;
display: flex;
+25 -2
View File
@@ -180,11 +180,12 @@
</template>
</el-table-column>
<el-table-column label="订单状态" width="100">
<el-table-column label="订单状态" width="120">
<template #default="{ row }">
<el-tag :type="getStatusTag(row.status)">
{{ getStatusText(row.status) }}
</el-tag>
<el-tag v-if="row.is_exempt === 1" type="warning" size="small" class="ml-1">豁免</el-tag>
</template>
</el-table-column>
@@ -270,6 +271,14 @@
>
删除
</el-button>
<el-button
v-perms="['order.order/setExempt']"
:type="row.is_exempt === 1 ? 'warning' : 'default'"
link
@click="handleToggleExempt(row)"
>
{{ row.is_exempt === 1 ? '取消豁免' : '设为豁免' }}
</el-button>
</template>
</el-table-column>
</el-table>
@@ -779,7 +788,8 @@ import {
orderActionLogs,
orderActionLogStats,
orderBatchAssignAssistant,
orderSplit
orderSplit,
orderSetExempt
} from '@/api/order'
import { getAssistants } from '@/api/tcm'
import { generateOrderQrcode } from '@/api/tcm'
@@ -1494,6 +1504,19 @@ const handleDelete = async (row: any) => {
}
}
const handleToggleExempt = async (row: any) => {
const newVal: 0 | 1 = row.is_exempt === 1 ? 0 : 1
const actionText = newVal === 1 ? '设为豁免' : '取消豁免'
try {
await feedback.confirm(`确定要${actionText}该支付单吗?豁免后关联此单的业务订单将跳过定金门槛校验。`)
await orderSetExempt({ id: row.id, is_exempt: newVal })
feedback.msgSuccess(`${actionText}成功`)
getLists()
} catch (error) {
// 用户取消操作
}
}
// 小程序码相关
const qrcodeDialogVisible = ref(false)
const qrcodeLoading = ref(false)
+67 -4
View File
@@ -49,6 +49,7 @@
v-model="form.channel_source"
placeholder="请选择渠道来源"
class="channel-source-select"
@change="onChannelSourceChange"
>
<el-option
v-for="item in channelOptions"
@@ -58,6 +59,20 @@
/>
</el-select>
</el-form-item>
<el-form-item
v-if="needsChannelSourceDetail"
label="自媒体补充:"
required
>
<el-input
v-model="form.channel_source_detail"
clearable
maxlength="128"
show-word-limit
placeholder="请输入自媒体相关补充内容"
class="channel-source-select"
/>
</el-form-item>
<!-- 预约医生 -->
<el-form-item label="预约医生:">
<div class="doctor-list">
@@ -233,9 +248,44 @@ const form = reactive({
date: '',
appointmentTime: '',
remark: '',
channel_source: '' as string
channel_source: '' as string,
channel_source_detail: '' as string
})
/** 仅这些渠道字典 name 需填「自媒体补充」(与后台字典名称完全一致) */
const CHANNEL_NAMES_REQUIRING_SELF_MEDIA_DETAIL = new Set([
'自媒体4H',
'自媒体3Q',
'自媒体3H',
'自媒体2H',
'自媒体2Q'
])
function channelNameRequiresSelfMediaDetail(name: string) {
return CHANNEL_NAMES_REQUIRING_SELF_MEDIA_DETAIL.has(String(name ?? '').trim())
}
/** 当前选中渠道字典名称(用于判断是否需填「自媒体补充」) */
const selectedChannelDictName = computed(() => {
const v = form.channel_source
if (v === '' || v == null) return ''
const row = channelOptions.value.find((item: any) => String(item.value) === String(v))
return row ? String(row.name ?? '').trim() : ''
})
/** 仅白名单内字典项需填写补充说明 */
const needsChannelSourceDetail = computed(() =>
channelNameRequiresSelfMediaDetail(selectedChannelDictName.value)
)
const onChannelSourceChange = (val: string) => {
const row = channelOptions.value.find((item: any) => String(item.value) === String(val))
const name = row ? String(row.name ?? '').trim() : ''
if (!channelNameRequiresSelfMediaDetail(name)) {
form.channel_source_detail = ''
}
}
// 生成未来7天的日期选项(只显示有排班的日期,且大于等于今天)
const dateOptions = computed<DateOption[]>(() => {
if (!selectedDoctorId.value || doctorRosterDates.value.length === 0) {
@@ -321,7 +371,8 @@ const canSubmit = computed(() => {
selectedDoctorId.value &&
form.date &&
form.appointmentTime &&
!!form.channel_source
!!form.channel_source &&
(!needsChannelSourceDetail.value || form.channel_source_detail.trim() !== '')
)
})
@@ -344,6 +395,7 @@ const open = async (patient: any) => {
form.appointmentTime = ''
form.remark = ''
form.channel_source = ''
form.channel_source_detail = ''
timeSlots.value = []
doctorRosterDates.value = []
lastVisit.value = ''
@@ -412,7 +464,13 @@ const loadLastVisit = async () => {
const loadChannelOptions = async () => {
try {
const data = await getDictData({ type: 'channels' })
channelOptions.value = (data?.channels || []).filter((row: any) => row.status !== 0)
const rows = (data?.channels || []).filter((row: any) => row.status !== 0)
rows.sort((a: any, b: any) => {
const ds = Number(b?.sort ?? 0) - Number(a?.sort ?? 0)
if (ds !== 0) return ds
return Number(b?.id ?? 0) - Number(a?.id ?? 0)
})
channelOptions.value = rows
} catch (e) {
console.error('加载渠道来源失败:', e)
channelOptions.value = []
@@ -612,6 +670,10 @@ const handleConfirm = async () => {
feedback.msgWarning('请选择渠道来源')
return
}
if (needsChannelSourceDetail.value && !form.channel_source_detail.trim()) {
feedback.msgWarning('请填写自媒体渠道补充信息')
return
}
if (blockedByTodayDuplicate.value) {
feedback.msgWarning(
'该患者今日已有挂号(已预约或已过号),不能重复预约今天,请改选其他日期。'
@@ -631,7 +693,8 @@ const handleConfirm = async () => {
appointment_time: form.appointmentTime,
appointment_type: form.appointmentType,
remark: form.remark,
channel_source: form.channel_source
channel_source: form.channel_source,
channel_source_detail: form.channel_source_detail.trim()
}
console.log('提交预约参数:', params)
@@ -105,7 +105,9 @@ function channelLabel(row: Record<string, any>) {
const raw = row.channel_source ?? row.channels ?? ''
if (raw === '' || raw === null || raw === undefined) return '—'
const key = String(raw)
return channelMap.value[key] || key
const base = channelMap.value[key] || key
const extra = String(row.channel_source_detail ?? '').trim()
return extra !== '' ? `${base}${extra}` : base
}
function sortRows(list: any[]) {
@@ -141,6 +143,8 @@ const load = async () => {
await loadChannels()
const res = await appointmentLists({
patient_id: props.diagnosisId,
/** 诊单维度拉挂号:后端豁免医生/医助与数据范围收窄 */
diag_scope_relax: 1,
page_no: 1,
page_size: 500
})
@@ -39,19 +39,313 @@
{{ formatTime(row.create_time) }}
</template>
</el-table-column>
<el-table-column label="操作" width="100" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['tcm.prescriptionOrder/detail']"
type="primary"
link
@click="openDetail(row.id)"
>查看详情</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-3">
<pagination v-model="pager" @change="getLists" />
</div>
</template>
<!-- 业务订单详情抽屉只读 order_list.vue 详情保持一致 -->
<el-drawer
v-model="detailVisible"
size="80%"
destroy-on-close
:close-on-click-modal="false"
append-to-body
>
<template #header>
<div class="flex items-center">
<span class="font-semibold text-lg">业务订单详情</span>
<el-tag v-if="detailData?.order_no" type="primary" effect="plain" round class="ml-3">{{ detailData.order_no }}</el-tag>
<el-tag v-if="detailData?.gancao_reciperl_order_no" type="success" effect="plain" round class="ml-2">甘草 {{ detailData.gancao_reciperl_order_no }}</el-tag>
</div>
</template>
<el-skeleton v-if="detailLoading" :rows="12" animated class="px-6 py-4" />
<div v-else-if="detailData" class="px-6 pb-6 overflow-y-auto">
<!-- 顶部数据概览 -->
<el-row :gutter="16" class="mb-5">
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="border border-gray-100 bg-gray-50/50">
<div class="text-gray-500 text-xs mb-1">总金额</div>
<div class="text-red-500 font-bold text-xl">¥{{ detailData.amount }}</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="border border-gray-100 bg-gray-50/50">
<div class="text-gray-500 text-xs mb-1">已付总额</div>
<div class="text-green-600 font-bold text-xl">¥{{ detailData.linked_pay_paid_total || 0 }}</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="border border-gray-100 bg-gray-50/50">
<div class="text-gray-500 text-xs mb-1">需代收</div>
<div class="font-bold text-xl" :class="detailAgencyToCollect > 0 ? 'text-amber-600' : 'text-gray-500'">¥{{ formatMoney(detailAgencyToCollect) }}</div>
</el-card>
</el-col>
<el-col :xs="12" :sm="6">
<el-card shadow="never" class="border border-gray-100 bg-gray-50/50">
<div class="text-gray-500 text-xs mb-1">已付笔数</div>
<div class="text-primary font-bold text-xl">{{ detailLinkedPayOrders.length }} </div>
</el-card>
</el-col>
</el-row>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<!-- 左侧处方单不含测试价格改患者信息药材明细 -->
<el-card shadow="never" class="border-gray-100 h-full relative overflow-hidden">
<div v-if="detailData.prescription_audit_status === 1" class="audit-stamp stamp-pass"><div class="stamp-inner">审核通过</div></div>
<div v-if="detailData.prescription_audit_status === 2" class="audit-stamp stamp-reject"><div class="stamp-inner">已驳回</div></div>
<template #header>
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<span class="font-medium text-[15px]">处方详情</span>
<span v-if="detailData.doctor_name" class="text-xs text-gray-500">
开方人<span class="text-primary font-medium">{{ detailData.doctor_name }}</span>
</span>
</div>
<span class="text-xs text-gray-400">ID: {{ detailData.prescription_id || '—' }}</span>
</div>
</template>
<template v-if="detailPrescription">
<el-descriptions :column="2" border size="small" class="bg-white">
<el-descriptions-item label="处方编号" :span="2">{{ detailPrescription.sn || '—' }}</el-descriptions-item>
<el-descriptions-item label="患者">{{ detailPrescription.patient_name || '—' }}</el-descriptions-item>
<el-descriptions-item label="性别 / 年龄">{{ detailPrescription.gender_desc || '—' }} · {{ detailPrescription.age ?? '—' }}</el-descriptions-item>
<el-descriptions-item label="手机">
<span :class="detailRecipientRxPhoneMismatch ? 'text-red-600 font-bold' : ''">{{ detailPrescription.phone || '—' }}</span>
<el-tag v-if="detailRecipientRxPhoneMismatch" type="danger" size="small" effect="dark" class="ml-2">与订单手机不一致</el-tag>
</el-descriptions-item>
<el-descriptions-item label="处方日期">{{ detailPrescription.prescription_date || '—' }}</el-descriptions-item>
<el-descriptions-item label="医师">{{ detailPrescription.doctor_name || '—' }}</el-descriptions-item>
<el-descriptions-item label="类型">{{ detailPrescription.prescription_type || '—' }}</el-descriptions-item>
<el-descriptions-item label="临床诊断" :span="2">{{ detailPrescription.clinical_diagnosis || '—' }}</el-descriptions-item>
<el-descriptions-item label="剂数 / 用法" :span="2">
{{ detailData.dose_count ?? detailPrescription.dose_count ?? '—' }} {{ detailData.dose_unit || '剂' }} ·
{{ detailPrescription.usage_instruction || detailPrescription.usage_method || '—' }}
</el-descriptions-item>
<el-descriptions-item label="处方金额">
<span class="text-red-500 font-medium">¥{{ detailPrescription.amount ?? '—' }}</span>
</el-descriptions-item>
<el-descriptions-item label="消费者审核">
<el-tag :type="consumerRxAuditTag(detailPrescription.audit_status)" size="small">{{ consumerRxAuditText(detailPrescription.audit_status) }}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="用量">
<template v-if="detailPrescription.dosage_amount">
{{ detailPrescription.dosage_amount }}{{ detailPrescription.dosage_unit || 'g' }}
<template v-if="detailPrescription.prescription_type === '浓缩水丸'">
· {{ Number(detailPrescription.dosage_bag_count) > 0 ? Number(detailPrescription.dosage_bag_count) : 1 }}
</template>
<span v-if="detailPrescription.prescription_type === '饮片' && detailPrescription.need_decoction !== null" class="ml-2 text-gray-500">
({{ detailPrescription.need_decoction ? '代煎' : '不代煎' }})
</span>
</template>
<template v-else></template>
</el-descriptions-item>
<el-descriptions-item label="服用方式">
<div class="flex flex-col gap-1.5 text-sm leading-relaxed">
<div>
<span class="text-gray-500">每天次数</span>
{{ detailPrescription.times_per_day ? detailPrescription.times_per_day + ' 次' : '—' }}
</div>
<div>
<span class="text-gray-500">处方开立</span>
{{ detailPrescription.usage_days != null && detailPrescription.usage_days !== '' ? detailPrescription.usage_days + ' 天' : '—' }}
</div>
<div>
<span class="text-gray-500">订单设置</span>
{{ detailData.medication_days != null && String(detailData.medication_days).trim() !== '' ? detailData.medication_days + ' 天' : '—' }}
</div>
</div>
</el-descriptions-item>
<el-descriptions-item label="状态" :span="2">
<el-tag :type="Number(detailPrescription.void_status) === 1 ? 'danger' : 'success'" size="small">{{ Number(detailPrescription.void_status) === 1 ? '已作废' : '正常' }}</el-tag>
</el-descriptions-item>
</el-descriptions>
</template>
<el-empty v-else description="无处方数据" :image-size="72" />
</el-card>
<!-- 右侧未关联 + 已关联支付单 -->
<div class="flex flex-col gap-4 h-full">
<el-card shadow="never" class="border-gray-100">
<template #header>
<div class="flex items-center justify-between">
<span class="font-medium text-[15px]">未关联的收款记录</span>
<span class="text-xs text-gray-400">本诊单下未被占用的支付单</span>
</div>
</template>
<el-table v-if="detailUnlinkedPayOrders.length" :data="detailUnlinkedPayOrders" size="small" border stripe max-height="280">
<el-table-column prop="id" label="ID" width="70" />
<el-table-column prop="order_no" label="单号" min-width="135" show-overflow-tooltip />
<el-table-column label="类型" width="90">
<template #default="{ row }">{{ row.order_type_desc || feeTypeText(row.order_type) }}</template>
</el-table-column>
<el-table-column label="金额" width="86" align="right">
<template #default="{ row }"><span class="text-red-500">¥{{ row.amount }}</span></template>
</el-table-column>
<el-table-column label="状态" width="82" align="center">
<template #default="{ row }">
<el-tag :type="payOrderStatusTag(row.status)" size="small">{{ row.status_desc || orderStatusText(row.status) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="creator_name" label="创建人" width="80" show-overflow-tooltip />
<el-table-column label="创建时间" min-width="136">
<template #default="{ row }">{{ formatOrderTime(row.create_time) }}</template>
</el-table-column>
</el-table>
<el-empty v-else description="无未关联的收款单" :image-size="60" />
</el-card>
<el-card shadow="never" class="border-gray-100 relative overflow-hidden">
<div v-if="detailData.payment_slip_audit_status === 1" class="audit-stamp stamp-pass"><div class="stamp-inner">审核通过</div></div>
<div v-if="detailData.payment_slip_audit_status === 2" class="audit-stamp stamp-reject"><div class="stamp-inner">已驳回</div></div>
<template #header>
<div class="flex items-center gap-3">
<span class="font-medium text-[15px]">关联收款记录</span>
<span v-if="detailData.creator_name" class="text-xs text-gray-500">创建人:<span class="text-primary font-medium">{{ detailData.creator_name }}</span></span>
</div>
</template>
<el-table v-if="detailLinkedPayOrders.length" :data="detailLinkedPayOrders" size="small" border stripe max-height="280">
<el-table-column prop="id" label="ID" width="70" />
<el-table-column prop="order_no" label="单号" min-width="135" show-overflow-tooltip />
<el-table-column label="类型" width="90">
<template #default="{ row }">{{ row.order_type_desc || feeTypeText(row.order_type) }}</template>
</el-table-column>
<el-table-column label="金额" width="86" align="right">
<template #default="{ row }"><span class="text-red-500">¥{{ row.amount }}</span></template>
</el-table-column>
<el-table-column label="状态" width="82" align="center">
<template #default="{ row }">
<el-tag :type="payOrderStatusTag(row.status)" size="small">{{ row.status_desc || orderStatusText(row.status) }}</el-tag>
</template>
</el-table-column>
<el-table-column prop="creator_name" label="创建人" width="80" show-overflow-tooltip />
<el-table-column label="创建时间" min-width="136">
<template #default="{ row }">{{ formatOrderTime(row.create_time) }}</template>
</el-table-column>
</el-table>
<el-empty v-else description="未关联收款单" :image-size="60" />
</el-card>
</div>
</div>
<!-- 履约与收货信息 -->
<el-card shadow="never" class="border-gray-100 mb-4">
<template #header><span class="font-medium text-[15px]">履约与收货信息</span></template>
<el-descriptions :column="3" border size="small">
<el-descriptions-item label="诊单ID" :span="3"><span class="font-mono">{{ detailData.diagnosis_id }}</span></el-descriptions-item>
<el-descriptions-item label="创建时间">{{ formatTime(detailData.create_time) }}</el-descriptions-item>
<el-descriptions-item label="业务订单创建人" :span="2">
<div v-if="detailData.creator_name" class="text-[13px] space-y-1">
<div><span class="font-medium text-gray-900">{{ detailData.creator_name || '—' }}</span></div>
<div v-if="detailOrderCreatorMetaLine" class="text-gray-600 text-xs">{{ detailOrderCreatorMetaLine }}</div>
</div>
<span v-else class="text-gray-400"></span>
</el-descriptions-item>
<el-descriptions-item label="创建人所属部门" :span="3">
<div v-if="detailOrderCreatorDeptBreadcrumbs.length" class="space-y-1.5">
<div v-for="(segments, idx) in detailOrderCreatorDeptBreadcrumbs" :key="idx">
<el-breadcrumb v-if="segments.length" class="text-[13px]" separator="/">
<el-breadcrumb-item v-for="(name, j) in segments" :key="j"><span class="text-gray-800">{{ name }}</span></el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
<span v-else class="text-gray-400"></span>
</el-descriptions-item>
<el-descriptions-item label="收货人">{{ detailData.recipient_name }}</el-descriptions-item>
<el-descriptions-item label="收货手机">
<span :class="detailRecipientRxPhoneMismatch ? 'text-red-600 font-bold font-mono' : 'font-mono'">{{ detailData.recipient_phone || '—' }}</span>
<el-tag v-if="detailRecipientRxPhoneMismatch" type="danger" size="small" effect="dark" class="ml-2">与处方手机不一致</el-tag>
</el-descriptions-item>
<el-descriptions-item label="收货地址">{{ detailFullAddress }}</el-descriptions-item>
<el-descriptions-item label="复诊">{{ detailData.is_follow_up ? '是' : '否' }}</el-descriptions-item>
<el-descriptions-item label="用药疗程">{{ detailData.medication_days ? detailData.medication_days + ' 天' : '—' }}</el-descriptions-item>
<el-descriptions-item label="上次医护">{{ detailData.prev_staff || '—' }}</el-descriptions-item>
<el-descriptions-item label="服务渠道">{{ detailData.service_channel || '—' }}</el-descriptions-item>
<el-descriptions-item label="费用类别">{{ feeTypeText(detailData.fee_type) }}</el-descriptions-item>
<el-descriptions-item label="快递单号">{{ detailData.tracking_number || '—' }}</el-descriptions-item>
<el-descriptions-item label="快递公司">{{ expressCompanyLabel(detailData.express_company) }}</el-descriptions-item>
<el-descriptions-item v-perms="['tcm.prescriptionOrder/editRemarkExtra']" label="药房备注" :span="3">{{ detailData.remark_extra || '' }}</el-descriptions-item>
<el-descriptions-item label="医助备注" :span="3">{{ detailData.remark_assistant || '—' }}</el-descriptions-item>
<el-descriptions-item label="处方审核意见" :span="3">{{ detailData.prescription_audit_remark || '—' }}</el-descriptions-item>
<el-descriptions-item label="支付审核意见" :span="3">{{ detailData.payment_slip_audit_remark || '—' }}</el-descriptions-item>
</el-descriptions>
</el-card>
<!-- 物流轨迹只读 -->
<el-card v-if="String(detailData.tracking_number || '').trim()" shadow="never" class="border-gray-100 mb-4">
<template #header><span class="font-medium text-[15px]">物流轨迹</span></template>
<div class="flex flex-wrap items-center gap-3 mb-4">
<el-input v-model="logisticsTracePhoneTail" clearable maxlength="20" placeholder="收件手机" class="w-[180px]" @keyup.enter="fetchLogisticsTrace" />
<el-select v-model="detailLogisticsExpress" placeholder="承运商" style="width: 140px">
<el-option label="自动识别" value="auto" />
<el-option label="顺丰速运" value="sf" />
<el-option label="京东快递" value="jd" />
<el-option label="极兔速递" value="jt" />
</el-select>
<el-button v-perms="['tcm.prescriptionOrder/logisticsTrace']" type="primary" plain size="default" :loading="logisticsTraceLoading" @click="fetchLogisticsTrace">刷新轨迹</el-button>
</div>
<div v-if="logisticsTraceLoading && !logisticsTracePayload" class="py-6 text-center text-sm text-gray-500">正在加载物流轨迹...</div>
<div v-else-if="logisticsTracePayload" class="bg-gray-50/50 p-4 rounded-md">
<div v-if="logisticsTracePayload.state_text" class="text-sm mb-4 font-medium flex items-center gap-2">
<span class="text-gray-800">状态{{ logisticsTracePayload.state_text }}</span>
<el-tag v-if="logisticsTracePayload.carrier_label" size="small" type="info">{{ logisticsTracePayload.carrier_label }}</el-tag>
</div>
<el-timeline v-if="logisticsTraceList.length" class="mt-2 pl-2">
<el-timeline-item v-for="(t, idx) in logisticsTraceList" :key="idx" :type="idx === 0 ? 'primary' : 'info'" :hollow="idx !== 0" :timestamp="t.time" placement="top">
<span :class="idx === 0 ? 'text-gray-800 font-medium' : 'text-gray-500'">{{ t.context }}</span>
</el-timeline-item>
</el-timeline>
<el-empty v-else description="暂无轨迹节点记录" :image-size="64" />
</div>
</el-card>
<!-- 操作日志 -->
<el-card v-perms="['tcm.prescriptionOrder/logs']" shadow="never" class="border-gray-100">
<template #header><span class="font-medium text-[15px]">操作日志</span></template>
<el-timeline v-if="detailLogs.length" class="mt-2 pl-2">
<el-timeline-item v-for="(log, idx) in detailLogs" :key="log.id" :type="idx === 0 ? 'primary' : 'info'" :hollow="idx !== 0" :timestamp="formatTime(log.create_time)" placement="top">
<div class="flex items-center gap-2 mb-1">
<span class="font-medium text-[13px]">{{ log.admin_name }}</span>
<el-tag size="small" type="info">{{ logActionText(log.action) }}</el-tag>
</div>
<span :class="idx === 0 ? 'text-gray-800 font-medium' : 'text-gray-500'">{{ log.summary }}</span>
</el-timeline-item>
</el-timeline>
<el-empty v-else description="暂无操作日志" :image-size="64" />
</el-card>
</div>
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { computed, watch } from 'vue'
import { computed, watch, ref } from 'vue'
import { usePaging } from '@/hooks/usePaging'
import { prescriptionOrderLists } from '@/api/tcm'
import {
prescriptionOrderLists,
prescriptionOrderDetail,
prescriptionOrderLogs,
prescriptionOrderLogisticsTrace,
prescriptionOrderPaidPayOrders
} from '@/api/tcm'
import { hasPermission } from '@/utils/perm'
import feedback from '@/utils/feedback'
import useUserStore from '@/stores/modules/user'
const userStore = useUserStore()
const props = defineProps<{
diagnosisId: number
@@ -83,11 +377,171 @@ const buildParams = () => {
queryParams.scene = 'diagnosis_edit'
}
// ─── 详情抽屉 ───
const detailVisible = ref(false)
const detailLoading = ref(false)
const detailData = ref<any>(null)
const detailLogs = ref<any[]>([])
const detailUnlinkedPayOrders = ref<any[]>([])
const detailPrescription = computed(() => {
const p = detailData.value?.prescription
return p && typeof p === 'object' ? p : null
})
const detailLinkedPayOrders = computed(() => {
const arr = detailData.value?.linked_pay_orders
return Array.isArray(arr) ? arr : []
})
const detailAgencyToCollect = computed(() => {
const d = detailData.value
if (!d) return 0
const total = Number(d.amount) || 0
const paid = Number(d.linked_pay_paid_total) || 0
return Math.round((total - paid) * 100) / 100
})
const detailRecipientRxPhoneMismatch = computed(() => {
const rx = normalizeBizPhone(detailPrescription.value?.phone)
const biz = normalizeBizPhone(detailData.value?.recipient_phone)
if (!rx || !biz) return false
return rx !== biz
})
const detailFullAddress = computed(() => {
const d = detailData.value
if (!d) return '—'
const parts = []
if (d.shipping_province) parts.push(d.shipping_province)
if (d.shipping_city) parts.push(d.shipping_city)
if (d.shipping_district) parts.push(d.shipping_district)
if (d.shipping_address) parts.push(d.shipping_address)
return parts.length > 0 ? parts.join(' ') : '—'
})
const detailOrderCreatorMetaLine = computed(() => {
const d = detailData.value
if (!d) return ''
const account = String(d.creator_account ?? '').trim()
const mobile = String(d.creator_mobile ?? '').trim()
const parts: string[] = []
if (account) parts.push(`登录账号:${account}`)
if (mobile) parts.push(`手机:${mobile}`)
return parts.join(' · ')
})
const detailOrderCreatorDeptBreadcrumbs = computed(() => {
const raw = String(detailData.value?.order_creator_dept_path ?? detailData.value?.diagnosis_creator_dept_path ?? '').trim()
if (!raw) return [] as string[][]
return raw.split('').map((s) => s.trim()).filter(Boolean)
.map((p) => p.includes(' / ') ? p.split(' / ').map((x) => x.trim()).filter(Boolean) : p.split('/').map((x) => x.trim()).filter(Boolean))
.filter((segs) => segs.length > 0)
})
// ─── 物流轨迹 ───
const detailLogisticsExpress = ref<string>('auto')
const logisticsTraceLoading = ref(false)
const logisticsTracePayload = ref<Record<string, any> | null>(null)
const logisticsTracePhoneTail = ref('')
const logisticsTraceList = computed(() => {
const p = logisticsTracePayload.value
if (!p || !Array.isArray(p.traces)) return []
return p.traces as Array<{ time: string; context: string }>
})
async function fetchLogisticsTrace() {
const id = Number(detailData.value?.id)
if (!id) return
logisticsTraceLoading.value = true
try {
const digits = String(logisticsTracePhoneTail.value || '').replace(/\D/g, '')
const params: { id: number; express_company?: string; phone_tail?: string } = {
id,
express_company: detailLogisticsExpress.value
}
if (digits.length >= 4) params.phone_tail = digits
const res: any = await prescriptionOrderLogisticsTrace(params)
logisticsTracePayload.value = (res?.data ?? res) as Record<string, any>
} catch {
logisticsTracePayload.value = null
} finally {
logisticsTraceLoading.value = false
}
}
// ─── 打开详情 ───
async function openDetail(id: number) {
detailData.value = null
detailUnlinkedPayOrders.value = []
logisticsTracePayload.value = null
detailLogisticsExpress.value = 'auto'
logisticsTracePhoneTail.value = ''
detailLogs.value = []
detailVisible.value = true
detailLoading.value = true
try {
const res: any = await prescriptionOrderDetail({ id })
const d = res?.data ?? res ?? null
detailData.value = d
if (d) {
detailLogisticsExpress.value = String(d.express_company || 'auto') || 'auto'
const dig = String(d.recipient_phone || '').replace(/\D/g, '')
logisticsTracePhoneTail.value = dig.length >= 4 ? dig : ''
if (String(d.tracking_number || '').trim()) fetchLogisticsTrace()
fetchLogs(id)
if (d.diagnosis_id) {
loadDetailUnlinkedPayOrders(d.diagnosis_id, id, d.pay_order_ids || [])
}
}
} catch (e: any) {
feedback.msgError(e?.message || '加载详情失败')
detailVisible.value = false
} finally {
detailLoading.value = false
}
}
async function loadDetailUnlinkedPayOrders(diagnosisId: number, prescriptionOrderId: number, linkedIds: number[]) {
if (!diagnosisId) { detailUnlinkedPayOrders.value = []; return }
try {
const res: any = await prescriptionOrderPaidPayOrders({ diagnosis_id: diagnosisId, prescription_order_id: prescriptionOrderId })
const lists = res?.lists ?? res?.data?.lists ?? []
detailUnlinkedPayOrders.value = Array.isArray(lists) ? lists.filter((item: any) => !linkedIds.includes(item.id)) : []
} catch { detailUnlinkedPayOrders.value = [] }
}
function canViewPrescriptionOrderLogs() {
const p = userStore.perms || []
return p.includes('*') || p.includes('tcm.prescriptionOrder/logs')
}
async function fetchLogs(id: number) {
if (!canViewPrescriptionOrderLogs()) { detailLogs.value = []; return }
try {
const res: any = await prescriptionOrderLogs({ id })
detailLogs.value = res?.data ?? res ?? []
} catch { detailLogs.value = [] }
}
// ─── 工具函数 ───
function normalizeBizPhone(v: unknown): string {
if (v === null || v === undefined) return ''
return String(v).replace(/\s/g, '').trim()
}
const formatAmount = (value: unknown) => {
const n = Number(value)
return Number.isFinite(n) ? n.toFixed(2) : '0.00'
}
function formatMoney(v: unknown) {
const n = Number(v)
return Number.isFinite(n) ? n.toFixed(2) : '0.00'
}
const formatTime = (value: unknown) => {
if (value === null || value === undefined || value === '') return '—'
if (typeof value === 'number' && value > 1e9 && value < 1e11) {
@@ -98,21 +552,53 @@ const formatTime = (value: unknown) => {
return String(value)
}
function formatOrderTime(v: unknown) {
if (v === null || v === undefined || v === '') return '—'
if (typeof v === 'string' && String(v).includes('-')) return String(v)
return formatTime(v)
}
function feeTypeText(t: number | undefined) {
const m: Record<number, string> = { 1: '药费', 2: '诊费', 3: '药费+诊费', 4: '其他' }
return m[Number(t)] ?? '—'
}
function expressCompanyLabel(v: unknown) {
const s = String(v || '').toLowerCase()
if (s === 'sf') return '顺丰速运'
if (s === 'jd') return '京东快递'
if (s === 'jt' || s === 'jtexpress') return '极兔速递'
return '自动识别'
}
function consumerRxAuditText(s: number | undefined) {
const n = Number(s)
if (n === 1) return '已通过'
if (n === 2) return '已驳回'
return '待审核'
}
function consumerRxAuditTag(s: number | undefined): 'success' | 'warning' | 'danger' | 'info' {
const n = Number(s)
if (n === 1) return 'success'
if (n === 2) return 'danger'
return 'warning'
}
function payOrderStatusTag(s: number | undefined): 'success' | 'warning' | 'danger' | 'info' {
const n = Number(s)
if (n === 2) return 'success'
if (n === 1) return 'warning'
return 'info'
}
function orderStatusText(s: number | undefined) {
const m: Record<number, string> = { 0: '待支付', 1: '待支付', 2: '已支付', 3: '已取消' }
return m[Number(s)] ?? '—'
}
const fulfillmentText = (s: number | undefined) => {
const m: Record<number, string> = {
1: '待双审通过',
2: '待发货',
3: '已完成',
4: '已取消',
5: '已发货',
6: '已签收',
7: '进行中',
8: '暂不制药',
9: '拒收',
10: '退款',
11: '保留药方',
12: '制药缓发'
}
const m: Record<number, string> = { 1: '待双审通过', 2: '待发货', 3: '已完成', 4: '已取消', 5: '已发货', 6: '已签收', 7: '进行中', 8: '暂不制药', 9: '拒收', 10: '退款', 11: '保留药方', 12: '制药缓发' }
return m[Number(s)] ?? '—'
}
@@ -126,14 +612,22 @@ const fulfillmentTagType = (s: number | undefined): 'success' | 'warning' | 'dan
return 'info'
}
function logActionText(act: string) {
const m: Record<string, string> = {
create: '创建', edit: '编辑', audit_rx_approve: '处方审核', audit_rx_reject: '处方审核',
audit_pay_approve: '支付审核', audit_pay_reject: '支付审核', fill_tracking: '填快递单',
ship: '确认发货', withdraw: '撤销', link_pay_order: '关联支付单',
revoke_rx_audit: '撤回处方审核', revoke_pay_audit: '撤回支付审核',
gancao_submit: '甘草下单', patch_rx_patient: '处方患者信息',
update_amount: '修改订单金额', complete: '完成订单'
}
return m[act] || act
}
watch(
() => [props.diagnosisId, patientIdNum.value] as const,
() => {
if (!patientIdAvailable.value) {
pager.lists = []
pager.count = 0
return
}
if (!patientIdAvailable.value) { pager.lists = []; pager.count = 0; return }
buildParams()
resetPage()
},
@@ -147,8 +641,25 @@ defineExpose({ refresh: () => getLists() })
.patient-order-list {
padding: 4px 0;
}
.po-empty-tip {
padding: 24px 0;
}
.audit-stamp {
position: absolute;
top: 12px;
right: 16px;
transform: rotate(15deg);
opacity: 0.15;
pointer-events: none;
z-index: 1;
}
.stamp-inner {
border: 3px solid currentColor;
border-radius: 8px;
padding: 4px 12px;
font-size: 18px;
font-weight: bold;
}
.stamp-pass { color: #22c55e; }
.stamp-reject { color: #ef4444; }
</style>
+6 -4
View File
@@ -151,12 +151,14 @@
stripe
>
<el-table-column type="selection" width="48" align="center" />
<el-table-column label="ID" min-width="50">
<el-table-column label="ID" min-width="70">
<template #default="{ row }">
<div class="patient-cell">
<!-- <div class="patient-avatar">{{ (row.patient_name || '患').charAt(0) }}</div> -->
<div class="patient-info">
<div class="patient-name">{{ row.id }}</div>
<div class="patient-name">
{{ row.id }}
<el-tag v-if="row.assign_read_at === null && row.assistant_id > 0" type="danger" size="small" effect="dark" class="ml-1">NEW</el-tag>
</div>
</div>
</div>
</template>
@@ -1352,7 +1354,7 @@ const handleSingleAssign = (row: any) => {
currentRow.value = row
batchAssignIds.value = []
// 确保类型一致,转换为数字
assignForm.value.assistant_id = row.assistant_id ? Number(row.assistant_id) : null
assignForm.value.assistant_id = Number(row.assistant_id) > 0 ? Number(row.assistant_id) : null
assignDialogVisible.value = true
}
@@ -130,6 +130,7 @@
</div>
<div class="dh5-card-sub">
#{{ row.id }} · {{ row.diagnosis_date_text || formatDateTime(row.create_time) }}
<span v-if="row.assign_read_at === null && row.assistant_id > 0" class="dh5-tag-new">NEW</span>
</div>
</div>
<div class="dh5-card-tags">
@@ -1672,6 +1673,18 @@ $dh5-card-bg: #ffffff;
flex-wrap: wrap;
}
.dh5-tag-new {
display: inline-block;
background: #ef4444;
color: #fff;
font-size: 10px;
font-weight: 700;
padding: 1px 4px;
border-radius: 3px;
margin-left: 4px;
vertical-align: middle;
}
.dh5-meta-gender,
.dh5-meta-age {
font-size: 12px;
+6 -4
View File
@@ -97,12 +97,14 @@
stripe
>
<el-table-column type="selection" width="48" align="center" />
<el-table-column label="ID" min-width="50">
<el-table-column label="ID" min-width="70">
<template #default="{ row }">
<div class="patient-cell">
<!-- <div class="patient-avatar">{{ (row.patient_name || '患').charAt(0) }}</div> -->
<div class="patient-info">
<div class="patient-name">{{ row.id }}</div>
<div class="patient-name">
{{ row.id }}
<el-tag v-if="row.assign_read_at === null && row.assistant_id > 0" type="danger" size="small" effect="dark" class="ml-1">NEW</el-tag>
</div>
</div>
</div>
</template>
@@ -1088,7 +1090,7 @@ const handleSingleAssign = (row: any) => {
assignMode.value = 'single'
currentRow.value = row
// 确保类型一致,转换为数字
assignForm.value.assistant_id = row.assistant_id ? Number(row.assistant_id) : null
assignForm.value.assistant_id = Number(row.assistant_id) > 0 ? Number(row.assistant_id) : null
assignDialogVisible.value = true
}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
open_basedir=/www/wwwroot/zyt/server/:/tmp/
@@ -557,6 +557,24 @@ class OrderController extends BaseAdminController
}
}
public function setExempt()
{
$id = (int) $this->request->post('id', 0);
$isExempt = (int) $this->request->post('is_exempt', 0);
if ($id <= 0) {
return $this->fail('参数错误');
}
if (!in_array($isExempt, [0, 1], true)) {
return $this->fail('is_exempt 值无效');
}
$result = OrderLogic::setExempt($id, $isExempt);
if (!$result) {
return $this->fail(OrderLogic::getError());
}
$this->logOrderAction($id, 'set_exempt', $isExempt === 1 ? '设置豁免权' : '取消豁免权');
return $this->success($isExempt === 1 ? '已设置豁免权' : '已取消豁免权');
}
private function logOrderAction(int $orderId, string $action, string $summary = ''): void
{
OrderActionLogLogic::record($orderId, (int) $this->adminId, $this->adminInfo, $action, $summary);
@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);
namespace app\adminapi\controller\stats;
use app\adminapi\controller\BaseAdminController;
use app\adminapi\logic\stats\YejiStatsLogic;
/**
* 提成结算业绩(独立于业绩看板 yejiStats 接口)
*
* - GET stats.commissionSettlement/overview
* - GET stats.commissionSettlement/orderLines
* - GET stats.commissionSettlement/confirmStatus
* - POST stats.commissionSettlement/saveReconcile
* - POST stats.commissionSettlement/confirmFinalize
* - GET stats.commissionSettlement/deptOptions
* - GET stats.commissionSettlement/channelOptions
*/
class CommissionSettlementController extends BaseAdminController
{
public function overview()
{
@set_time_limit(120);
$params = $this->request->get();
return $this->data(YejiStatsLogic::commissionSettlementOverview($params, $this->adminId, $this->adminInfo));
}
public function orderLines()
{
@set_time_limit(120);
return $this->data(YejiStatsLogic::commissionSettlementOrderLines($this->request->get(), $this->adminId, $this->adminInfo));
}
public function confirmStatus()
{
return $this->data(YejiStatsLogic::commissionSettlementConfirmStatus($this->request->get(), $this->adminId, $this->adminInfo));
}
public function saveReconcile()
{
return $this->data(YejiStatsLogic::commissionSettlementSaveReconcile($this->request->post(), $this->adminId, $this->adminInfo));
}
public function confirmFinalize()
{
@set_time_limit(120);
return $this->data(YejiStatsLogic::commissionSettlementConfirmFinalize($this->request->post(), $this->adminId, $this->adminInfo));
}
public function deptOptions()
{
return $this->data(YejiStatsLogic::deptOptions($this->adminId, $this->adminInfo));
}
public function channelOptions()
{
return $this->data(YejiStatsLogic::channelOptions(false));
}
}
@@ -117,6 +117,7 @@ class DiagnosisController extends BaseAdminController
$params = (new DiagnosisValidate())->goCheck('id');
$result = DiagnosisLogic::detail($params);
DiagnosisLogic::markAssignRead((int) ($params['id'] ?? 0), $this->adminId);
return $this->data($result);
}
@@ -135,7 +136,7 @@ class DiagnosisController extends BaseAdminController
if (empty($result)) {
return $this->fail(DiagnosisLogic::getError() ?: '诊单不存在或无权访问');
}
DiagnosisLogic::markAssignRead((int) ($params['id'] ?? 0), $this->adminId);
return $this->data($result);
}
@@ -20,6 +20,16 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
{
use HasDataScopeFilter;
/**
* 诊单编辑/详情「挂号记录」Tab:按诊单 ID 拉全量挂号,不做医生/医助角色收窄与数据范围过滤。
* 须同时传 patient_id(挂号表存的是诊单 id)与本开关,避免列表页被滥用拓宽可见范围。
*/
private function appointmentListsScopeRelaxedForDiagnosis(): bool
{
return (int) ($this->params['diag_scope_relax'] ?? 0) === 1
&& (int) ($this->params['patient_id'] ?? 0) > 0;
}
/**
* 数据隔离:医生或医助(u.assistant_id = diag.assistant_id)命中可见集合;progress_board 场景放开(看板跨医生查看)
*/
@@ -28,6 +38,9 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
if ($progressBoard) {
return;
}
if ($this->appointmentListsScopeRelaxedForDiagnosis()) {
return;
}
if (!$this->dataScopeShouldApply()) {
return;
}
@@ -128,7 +141,8 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
// 面诊进度看板:可切换查看各医生挂号,不按当前账号角色收窄
$progressBoard = (int) ($this->params['progress_board'] ?? 0) === 1;
if (!$progressBoard) {
$diagScopeRelax = $this->appointmentListsScopeRelaxedForDiagnosis();
if (!$progressBoard && !$diagScopeRelax) {
// 如果是医生角色(role_id=1),只显示挂自己号的预约
if (in_array(1, $roleIds)) {
$query->where('a.doctor_id', $this->adminId);
@@ -288,7 +302,8 @@ class AppointmentLists extends BaseAdminDataLists implements ListsSearchInterfac
}
$progressBoard = (int) ($this->params['progress_board'] ?? 0) === 1;
if (!$progressBoard) {
$diagScopeRelax = $this->appointmentListsScopeRelaxedForDiagnosis();
if (!$progressBoard && !$diagScopeRelax) {
if (in_array(1, $roleIds)) {
$query->where('a.doctor_id', $this->adminId);
}
@@ -177,14 +177,14 @@ class DiagnosisLists extends BaseAdminDataLists implements ListsSearchInterface
$isCompletedTab = !$pendingWideSearch && isset($this->params['completed_appointment']) && (string) $this->params['completed_appointment'] === '1';
if ($isCompletedTab) {
$maxCompletedAptExpr = '(SELECT MAX(CONCAT(apt.appointment_date, \' \', IFNULL(NULLIF(TRIM(apt.appointment_time), \'\'), \'00:00:00\'))) FROM ' . $aptTbl . ' apt WHERE apt.patient_id = ' . $diagTbl . '.id AND apt.status = 3' . $minAptDateCond . ')';
$orderRaw = 'IFNULL(' . $maxCompletedAptExpr . ", '1970-01-01 00:00:00') DESC, {$diagTbl}.id DESC";
$orderRaw = $diagTbl . '.assign_read_at IS NULL DESC, IFNULL(' . $maxCompletedAptExpr . ", '1970-01-01 00:00:00') DESC, {$diagTbl}.id DESC";
} else {
$orderRaw = 'CASE IFNULL(' . $minAptStatusExpr . ', 999) WHEN 4 THEN 1 WHEN 1 THEN 2 WHEN 3 THEN 3 ELSE 4 END ASC, IFNULL(' . $minAptExpr . ", '9999-12-31 23:59:59') ASC, {$diagTbl}.id DESC";
$orderRaw = $diagTbl . '.assign_read_at IS NULL DESC, CASE IFNULL(' . $minAptStatusExpr . ', 999) WHEN 4 THEN 1 WHEN 1 THEN 2 WHEN 3 THEN 3 ELSE 4 END ASC, IFNULL(' . $minAptExpr . ", '9999-12-31 23:59:59') ASC, {$diagTbl}.id DESC";
}
$lists = $query
->with(['DiagnosisViewRecord'])
->field(['id', 'patient_id', 'patient_name', 'id_card', 'phone', 'gender', 'age', 'diagnosis_date', 'diagnosis_type', 'syndrome_type', 'assistant_id', 'status', 'create_time', 'update_time'])
->field(['id', 'patient_id', 'patient_name', 'id_card', 'phone', 'gender', 'age', 'diagnosis_date', 'diagnosis_type', 'syndrome_type', 'assistant_id', 'assign_read_at', 'status', 'create_time', 'update_time'])
->append(['gender_desc', 'status_desc', 'diagnosis_date_text'])
->orderRaw($orderRaw)
->limit($this->limitOffset, $this->limitLength)
@@ -117,6 +117,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
/**
* 业绩看板:仅列出二中心复诊口径下的业务订单(须同时传 assistant_id、start_time、end_timerevisit_slot=0 为全部复诊分项合计)。
* admin 维度按订单创建人 o.creator_id(与部门表复诊列、排行榜复诊列同口径)。
*/
private function applyYejiErCenterRevisitOrderFilter($query): void
{
@@ -138,7 +139,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
if ($t0 === false || $t1 === false) {
return;
}
$ids = DeptLogic::listErCenterRevisitOrderIdsForAssistant(
$ids = DeptLogic::listErCenterRevisitOrderIdsForCreator(
$assistantId,
$slot,
(int) $t0,
@@ -552,7 +553,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
unset($item);
if ((int) ($this->params['yeji_order_drawer'] ?? 0) === 1) {
PrescriptionOrderLogic::appendLinkedAppointmentsToListRows($lists);
PrescriptionOrderLogic::appendLinkedAppointmentsToListRows($lists, $this->params);
}
return $lists;
@@ -870,16 +871,23 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
$query->whereExists("SELECT 1 FROM {$rxTbl} rx WHERE rx.id = {$poTbl}.prescription_id AND rx.delete_time IS NULL AND rx.creator_id = {$doctorId}");
}
/** 业绩看板入口(yeji_order_drawer=1)所有筛选统一按订单创建人;其它入口(处方订单列表 / 患者跟进等)保留旧口径(创建人 ∪ 诊单医助) */
$yejiPanel = (int) ($this->params['yeji_order_drawer'] ?? 0) === 1;
if (isset($this->params['assistant_id']) && (int) $this->params['assistant_id'] > 0) {
$assistantId = (int) $this->params['assistant_id'];
$diagTbl = (new Diagnosis())->getTable();
$query->where(function ($q) use ($poTbl, $diagTbl, $assistantId) {
$q->where('creator_id', $assistantId);
$q->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id`"
. " AND dg.`delete_time` IS NULL AND dg.`assistant_id` = {$assistantId})"
);
});
if ($yejiPanel) {
$query->where('creator_id', $assistantId);
} else {
$diagTbl = (new Diagnosis())->getTable();
$query->where(function ($q) use ($poTbl, $diagTbl, $assistantId) {
$q->where('creator_id', $assistantId);
$q->whereOrRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg WHERE dg.`id` = `{$poTbl}`.`diagnosis_id`"
. " AND dg.`delete_time` IS NULL AND dg.`assistant_id` = {$assistantId})"
);
});
}
}
if (isset($this->params['assistant_dept_id']) && $this->params['assistant_dept_id'] !== '' && (int) $this->params['assistant_dept_id'] > 0) {
@@ -898,6 +906,24 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
return;
}
$yejiTableRowDeptIds = [];
if (isset($this->params['yeji_table_row_dept_ids']) && trim((string) $this->params['yeji_table_row_dept_ids']) !== '') {
foreach (explode(',', (string) $this->params['yeji_table_row_dept_ids']) as $p) {
$v = (int) trim((string) $p);
if ($v > 0) {
$yejiTableRowDeptIds[] = $v;
}
}
}
if ((int) ($this->params['yeji_order_drawer'] ?? 0) === 1 && $yejiTableRowDeptIds !== []) {
YejiStatsLogic::applyPrescriptionOrderListAlignedWinnerDeptFilter(
$query,
(int) $this->params['assistant_dept_id'],
$yejiTableRowDeptIds
);
return;
}
$rootDeptId = (int) $this->params['assistant_dept_id'];
$deptIds = DeptLogic::getSelfAndDescendantIds($rootDeptId);
$deptIds = array_values(array_filter(array_map('intval', $deptIds), static function (int $id): bool {
@@ -909,23 +935,38 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
return;
}
$inList = implode(',', $deptIds);
$diagTbl = (new Diagnosis())->getTable();
$adTbl = (new AdminDept())->getTable();
$query->where(function ($q) use ($poTbl, $diagTbl, $adTbl, $inList) {
$q->whereExists(
"SELECT 1 FROM `{$adTbl}` ad INNER JOIN `{$diagTbl}` dg ON ad.admin_id = dg.assistant_id AND dg.delete_time IS NULL "
. "WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` AND ad.dept_id IN ({$inList})"
<<<<<<< HEAD
if ($yejiPanel) {
/** 业绩看板部门侧栏:仅订单创建人人事部门 ∈ 子树(与「合计业绩」/「接诊诊单」/「复诊」聚合同口径) */
$query->whereExists(
"SELECT 1 FROM `{$adTbl}` adc WHERE adc.`admin_id` = `{$poTbl}`.`creator_id` AND adc.`dept_id` IN ({$inList})"
);
$q->whereExists(
"SELECT 1 FROM `{$adTbl}` adc WHERE adc.`admin_id` = `{$poTbl}`.`creator_id` AND adc.`dept_id` IN ({$inList})",
'OR'
);
});
} else {
$diagTbl = (new Diagnosis())->getTable();
$query->where(function ($q) use ($poTbl, $diagTbl, $adTbl, $inList) {
$q->whereExists(
"SELECT 1 FROM `{$adTbl}` ad INNER JOIN `{$diagTbl}` dg ON ad.admin_id = dg.assistant_id AND dg.delete_time IS NULL "
. "WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` AND ad.dept_id IN ({$inList})"
);
$q->whereExists(
"SELECT 1 FROM `{$adTbl}` adc WHERE adc.`admin_id` = `{$poTbl}`.`creator_id` AND adc.`dept_id` IN ({$inList})",
'OR'
);
});
}
=======
$poRef = '`' . str_replace('`', '', $poTbl) . '`';
$query->whereRaw(
YejiStatsLogic::sqlPrescriptionOrderListDeptSubtreeMatchCreatorFirst($poRef, $diagTbl, $adTbl, $inList)
);
>>>>>>> master
}
}
/**
* 业绩看板侧栏:只保留「业绩归属医助」落在给定 admin_id 集合的订单(与 YejiStatsLogic::sqlPerformanceAttributionAdminExpr 一致)。
* 业绩看板侧栏:只保留「业绩归属医助」落在给定 admin_id 集合的订单
* (与 YejiStatsLogic::sqlPerformanceAttributionAdminExpr 一致——按订单创建人)。
*
* @param int[] $adminIds
*/
@@ -939,18 +980,7 @@ class PrescriptionOrderLists extends BaseAdminDataLists implements ListsSearchIn
return;
}
$poTbl = (new PrescriptionOrder())->getTable();
$diagTbl = (new Diagnosis())->getTable();
$rxTbl = (new Prescription())->getTable();
$inList = implode(',', $adminIds);
$query->whereRaw(
"EXISTS (SELECT 1 FROM `{$diagTbl}` dg "
. "LEFT JOIN `{$rxTbl}` rx ON rx.`id` = `{$poTbl}`.`prescription_id` AND rx.`delete_time` IS NULL "
. "WHERE dg.`id` = `{$poTbl}`.`diagnosis_id` AND dg.`delete_time` IS NULL AND `{$poTbl}`.`diagnosis_id` > 0 AND "
. '(CASE WHEN dg.`assistant_id` > 0 THEN dg.`assistant_id` '
. "WHEN `{$poTbl}`.`creator_id` > 0 AND (rx.`id` IS NULL OR NOT (`{$poTbl}`.`creator_id` <=> rx.`creator_id`)) THEN `{$poTbl}`.`creator_id` "
. 'ELSE 0 END) IN (' . $inList . '))'
);
$query->whereIn('creator_id', $adminIds);
}
/**
+53 -70
View File
@@ -219,21 +219,24 @@ class DeptLogic extends BaseLogic
}
return $q
->field(['o.diagnosis_id', 'o.create_time', 'o.id', 'dg.assistant_id'])
->field(['o.diagnosis_id', 'o.create_time', 'o.id', 'dg.assistant_id', 'o.creator_id'])
->order(['o.diagnosis_id' => 'asc', 'o.create_time' => 'asc', 'o.id' => 'asc'])
->select()
->toArray();
}
/**
* 二中心子树:各部门复诊 rollup;同时返回按诊单医助聚合的分项(供医助排行榜)。
* 二中心子树:各部门复诊 rollup(按订单创建人 creator_id 归属)。
* 候选订单仍要求 dg.assistant_id > 0(保持「er-center 案例 = 有医助的诊单」的定义),
* **复诊归属**改为订单创建人——leaf 部门归属取 creator_id 在二中心子树内的 canonical 部门,
* 并产出 by_creator_slots 供医助排行榜复诊列复用,与诊金 / 接诊诊单口径完全一致。
*
* @param list<int> $subtreeDeptIds
*
* @return array{
* totals: array<int, int>,
* slots: array<int, array<int, int>>,
* by_assistant_slots: array<int, array<int, int>>
* by_creator_slots: array<int, array<int, int>>
* }
*/
private static function computeErCenterRevisitFullPack(
@@ -249,12 +252,12 @@ class DeptLogic extends BaseLogic
$emptyTotals[$did] = 0;
}
if ($subtreeDeptIds === []) {
return ['totals' => [], 'slots' => [], 'by_assistant_slots' => []];
return ['totals' => [], 'slots' => [], 'by_creator_slots' => []];
}
$subtreeSet = array_fill_keys($subtreeDeptIds, true);
$orderRows = self::fetchErCenterRevisitCandidateOrders($orderStartTs, $orderEndTs);
if ($orderRows === []) {
return ['totals' => $emptyTotals, 'slots' => $emptySlots, 'by_assistant_slots' => []];
return ['totals' => $emptyTotals, 'slots' => $emptySlots, 'by_creator_slots' => []];
}
$byPatient = [];
@@ -266,29 +269,30 @@ class DeptLogic extends BaseLogic
$byPatient[$pid][] = $r;
}
$assistantNeed = [];
$creatorNeed = [];
foreach ($byPatient as $orders) {
$n = \count($orders);
for ($i = 1; $i < $n; $i++) {
$aid = (int) ($orders[$i]['assistant_id'] ?? 0);
if ($aid > 0) {
$assistantNeed[$aid] = true;
$cid = (int) ($orders[$i]['creator_id'] ?? 0);
if ($cid > 0) {
$creatorNeed[$cid] = true;
}
}
}
$assistantIds = array_keys($assistantNeed);
$canonicalDept = self::buildAssistantCanonicalDeptInSubtree($assistantIds, $subtreeSet);
$creatorIds = array_keys($creatorNeed);
/** 复用 buildAssistantCanonicalDeptInSubtree —— 该方法实际是 admin → 子树内 canonical 部门,与 admin 角色无关 */
$canonicalDept = self::buildAssistantCanonicalDeptInSubtree($creatorIds, $subtreeSet);
/** @var array<int, array<int, int>> $leafByDeptSlot dept_id => [ slot => cnt ]slot≥2 */
$leafByDeptSlot = [];
/** @var array<int, array<int, int>> $byAssistantSlot */
$byAssistantSlot = [];
/** @var array<int, array<int, int>> $byCreatorSlot 复诊按订单创建人聚合(与诊金/接诊诊单口径一致) */
$byCreatorSlot = [];
foreach ($byPatient as $orders) {
$n = \count($orders);
for ($i = 1; $i < $n; $i++) {
$slot = $i + 1;
$aid = (int) ($orders[$i]['assistant_id'] ?? 0);
$deptId = $canonicalDept[$aid] ?? null;
$cid = (int) ($orders[$i]['creator_id'] ?? 0);
$deptId = $canonicalDept[$cid] ?? null;
if ($deptId === null || !isset($subtreeSet[$deptId])) {
continue;
}
@@ -296,11 +300,11 @@ class DeptLogic extends BaseLogic
$leafByDeptSlot[$deptId] = [];
}
$leafByDeptSlot[$deptId][$slot] = ($leafByDeptSlot[$deptId][$slot] ?? 0) + 1;
if ($aid > 0) {
if (!isset($byAssistantSlot[$aid])) {
$byAssistantSlot[$aid] = [];
if ($cid > 0) {
if (!isset($byCreatorSlot[$cid])) {
$byCreatorSlot[$cid] = [];
}
$byAssistantSlot[$aid][$slot] = ($byAssistantSlot[$aid][$slot] ?? 0) + 1;
$byCreatorSlot[$cid][$slot] = ($byCreatorSlot[$cid][$slot] ?? 0) + 1;
}
}
}
@@ -313,16 +317,16 @@ class DeptLogic extends BaseLogic
$rollupTotals[$id] = array_sum($rollupSlots[$id] ?? []);
}
foreach ($byAssistantSlot as $aid => $sm) {
foreach ($byCreatorSlot as $cid => $sm) {
if ($sm !== []) {
ksort($byAssistantSlot[$aid], SORT_NUMERIC);
ksort($byCreatorSlot[$cid], SORT_NUMERIC);
}
}
return [
'totals' => $rollupTotals,
'slots' => $rollupSlots,
'by_assistant_slots' => $byAssistantSlot,
'by_creator_slots' => $byCreatorSlot,
];
}
@@ -345,11 +349,11 @@ class DeptLogic extends BaseLogic
}
/**
* 二中心子树内:各医助成交的复诊业务单笔数(合计 + 复诊2/3/…分项),口径与部门 rollup 同源
* 二中心子树复诊:按订单创建人 creator_id 聚合(与部门 rollup 同源,与诊金/接诊诊单口径一致)
*
* @return array{totals: array<int, int>, slots: array<int, array<int, int>>}
*/
public static function getErCenterRevisitCountsByAssistant(?int $orderStartTs = null, ?int $orderEndTs = null): array
public static function getErCenterRevisitCountsByCreator(?int $orderStartTs = null, ?int $orderEndTs = null): array
{
$erRoots = self::findErCenterRootDeptIds();
$subtreeIds = self::unionErCenterSubtreeDeptIds($erRoots);
@@ -357,42 +361,36 @@ class DeptLogic extends BaseLogic
return ['totals' => [], 'slots' => []];
}
$pack = self::computeErCenterRevisitFullPack($subtreeIds, $orderStartTs, $orderEndTs);
$by = $pack['by_assistant_slots'];
$by = $pack['by_creator_slots'];
$totals = [];
$slots = [];
foreach ($by as $aid => $slotMap) {
$aid = (int) $aid;
$totals[$aid] = (int) array_sum($slotMap);
$slots[$aid] = $slotMap;
foreach ($by as $cid => $slotMap) {
$cid = (int) $cid;
$totals[$cid] = (int) array_sum($slotMap);
$slots[$cid] = $slotMap;
}
return ['totals' => $totals, 'slots' => $slots];
}
/**
* 某医助在区间内、计入二中心复诊的业务订单 id(用于看板侧栏按复诊笔数下钻)。
* 二中心子树复诊:列出某「订单创建人」在区间内、复诊序列(slot≥2)命中的业务订单 id(用于看板侧栏按复诊笔数下钻)。
* $revisitSlot = 0 表示累计全部复诊(第 2 笔起);≥2 时仅该分项。
*
* @return list<int>
*/
public static function listErCenterRevisitOrderIdsForAssistant(
int $assistantId,
public static function listErCenterRevisitOrderIdsForCreator(
int $creatorId,
int $revisitSlot,
int $orderStartTs,
int $orderEndTs
): array {
if ($assistantId <= 0 || $orderStartTs <= 0 || $orderEndTs < $orderStartTs) {
if ($creatorId <= 0 || $orderStartTs <= 0 || $orderEndTs < $orderStartTs) {
return [];
}
if ($revisitSlot < 0 || $revisitSlot === 1) {
return [];
}
$erRoots = self::findErCenterRootDeptIds();
$subtreeIds = self::unionErCenterSubtreeDeptIds($erRoots);
if ($subtreeIds === []) {
return [];
}
$subtreeSet = array_fill_keys($subtreeIds, true);
$orderRows = self::fetchErCenterRevisitCandidateOrders($orderStartTs, $orderEndTs);
if ($orderRows === []) {
return [];
@@ -405,31 +403,16 @@ class DeptLogic extends BaseLogic
}
$byPatient[$pid][] = $r;
}
$assistantNeed = [];
foreach ($byPatient as $orders) {
$n = \count($orders);
for ($i = 1; $i < $n; $i++) {
$aid = (int) ($orders[$i]['assistant_id'] ?? 0);
if ($aid > 0) {
$assistantNeed[$aid] = true;
}
}
}
$canonicalDept = self::buildAssistantCanonicalDeptInSubtree(array_keys($assistantNeed), $subtreeSet);
$ids = [];
foreach ($byPatient as $orders) {
$n = \count($orders);
for ($i = 1; $i < $n; $i++) {
$slot = $i + 1;
$aid = (int) ($orders[$i]['assistant_id'] ?? 0);
if ($aid !== $assistantId) {
continue;
}
if ($revisitSlot > 0 && $slot !== $revisitSlot) {
continue;
}
$dcan = $canonicalDept[$aid] ?? null;
if ($dcan === null || !isset($subtreeSet[$dcan])) {
$cid = (int) ($orders[$i]['creator_id'] ?? 0);
if ($cid !== $creatorId) {
continue;
}
$oid = (int) ($orders[$i]['id'] ?? 0);
@@ -443,8 +426,8 @@ class DeptLogic extends BaseLogic
}
/**
* 某展示部门行(组织架构上含下级 rollup)内,二中心复诊按诊单医助拆解笔数。
* 与看板行内「复诊」列口径一致:诊单下订单序列第 2 笔起;医助 canonical 部门须落在二中心子树且在该部门行的子树内。
* 某展示部门行(组织架构上含下级 rollup)内,二中心复诊按**订单创建人**拆解笔数。
* 与看板行内「复诊」列口径一致:订单序列第 2 笔起;创建人 canonical 部门须落在二中心子树且在该部门行的子树内。
*
* @return array{rows: list<array{admin_id: int, name: string, order_count: int}>}
*/
@@ -484,17 +467,17 @@ class DeptLogic extends BaseLogic
}
$byPatient[$pid][] = $r;
}
$assistantNeed = [];
$creatorNeed = [];
foreach ($byPatient as $orders) {
$n = \count($orders);
for ($i = 1; $i < $n; $i++) {
$aid = (int) ($orders[$i]['assistant_id'] ?? 0);
if ($aid > 0) {
$assistantNeed[$aid] = true;
$cid = (int) ($orders[$i]['creator_id'] ?? 0);
if ($cid > 0) {
$creatorNeed[$cid] = true;
}
}
}
$canonicalDept = self::buildAssistantCanonicalDeptInSubtree(array_keys($assistantNeed), $erSubtreeSet);
$canonicalDept = self::buildAssistantCanonicalDeptInSubtree(array_keys($creatorNeed), $erSubtreeSet);
/** @var array<int, int> $counts */
$counts = [];
foreach ($byPatient as $orders) {
@@ -504,15 +487,15 @@ class DeptLogic extends BaseLogic
if ($revisitSlot > 0 && $slot !== $revisitSlot) {
continue;
}
$aid = (int) ($orders[$i]['assistant_id'] ?? 0);
if ($aid <= 0) {
$cid = (int) ($orders[$i]['creator_id'] ?? 0);
if ($cid <= 0) {
continue;
}
$canon = $canonicalDept[$aid] ?? null;
$canon = $canonicalDept[$cid] ?? null;
if ($canon === null || !isset($erSubtreeSet[$canon]) || !isset($descFlip[$canon])) {
continue;
}
$counts[$aid] = ($counts[$aid] ?? 0) + 1;
$counts[$cid] = ($counts[$cid] ?? 0) + 1;
}
}
if ($counts === []) {
@@ -527,10 +510,10 @@ class DeptLogic extends BaseLogic
->column('name', 'id');
}
$rows = [];
foreach ($counts as $aid => $cnt) {
foreach ($counts as $cid => $cnt) {
$rows[] = [
'admin_id' => (int) $aid,
'name' => (string) ($nameRows[$aid] ?? ('#' . $aid)),
'admin_id' => (int) $cid,
'name' => (string) ($nameRows[$cid] ?? ('#' . $cid)),
'order_count' => (int) $cnt,
];
}
@@ -28,6 +28,20 @@ use think\facade\Log;
*/
class AppointmentLogic extends BaseLogic
{
/** 仅这些字典名称需填写 channel_source_detail(与 admin 预约弹窗白名单一致,按 name 全等) */
private const CHANNEL_NAMES_REQUIRING_SOURCE_DETAIL = [
'自媒体4H',
'自媒体3Q',
'自媒体3H',
'自媒体2H',
'自媒体2Q',
];
private static function channelDictNameRequiresSourceDetail(string $name): bool
{
return in_array($name, self::CHANNEL_NAMES_REQUIRING_SOURCE_DETAIL, true);
}
/**
* @notes 获取可用时间段
* @param array $params
@@ -233,6 +247,21 @@ class AppointmentLogic extends BaseLogic
Db::rollback();
return false;
}
$chSrc = trim((string) ($params['channel_source'] ?? ''));
$chDetail = trim((string) ($params['channel_source_detail'] ?? ''));
$channelDictName = trim((string) (DictData::where('type_value', 'channels')
->where('value', $chSrc)
->value('name') ?? ''));
if ($channelDictName !== '' && self::channelDictNameRequiresSourceDetail($channelDictName)) {
if ($chDetail === '') {
self::setError('请填写自媒体渠道补充信息');
Db::rollback();
return false;
}
}
$data = [
'patient_id' => $params['patient_id'],
'assistant_id'=>$params['assistant_id'],
@@ -244,7 +273,8 @@ class AppointmentLogic extends BaseLogic
'appointment_type' => $params['appointment_type'] ?? 'video',
'remark' => $params['remark'] ?? '',
// 表字段为 channel_source(与字典 type_value=channels 的 value 一致);勿再写入不存在的 channels 列
'channel_source' => trim((string) ($params['channel_source'] ?? '')),
'channel_source' => $chSrc,
'channel_source_detail' => $chDetail,
'status' => 1,
'create_time' => time(),
'update_time' => time(),
+13 -1
View File
@@ -1213,7 +1213,7 @@ class OrderLogic
}
$rows = $q
->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark'])
->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark', 'is_exempt'])
->order('id', 'desc')
->select()
->toArray();
@@ -1400,4 +1400,16 @@ class OrderLogic
'errors' => $errors,
];
}
public static function setExempt(int $id, int $isExempt): bool
{
$order = Order::find($id);
if (!$order) {
self::setError('订单不存在');
return false;
}
$order->is_exempt = $isExempt;
$order->save();
return true;
}
}
File diff suppressed because it is too large Load Diff
@@ -535,6 +535,19 @@ class DiagnosisLogic extends BaseLogic
return 0;
}
public static function markAssignRead(int $diagnosisId, int $adminId): void
{
if ($diagnosisId <= 0 || $adminId <= 0) {
return;
}
Db::name('tcm_diagnosis')
->where('id', $diagnosisId)
->where('assistant_id', $adminId)
->whereNull('assign_read_at')
->whereNull('delete_time')
->update(['assign_read_at' => time()]);
}
/**
* @notes 指派医助(每次成功更新写入一条操作记录,批量指派为多次接口调用各记一条)。
* **原医助**:优先诊单 `assistant_id`;若为 0 且本次为指派到某人,则从**最近一条**指派日志推断(覆盖发货释放后库为 0、业务上仍有「前任」医助的情况)。
@@ -588,7 +601,10 @@ class DiagnosisLogic extends BaseLogic
Db::name('tcm_diagnosis')
->where('id', $id)
->whereNull('delete_time')
->update(['assistant_id' => $toAssistantId]);
->update([
'assistant_id' => $toAssistantId,
'assign_read_at' => $toAssistantId > 0 ? null : 0,
]);
$req = request();
$admin = $req->adminInfo ?? [];
@@ -10,6 +10,7 @@ use app\common\model\tcm\Prescription;
use app\common\model\tcm\PrescriptionOrder;
use app\common\model\tcm\Diagnosis;
use app\common\service\wechat\WechatWorkAppMessageService;
use app\adminapi\logic\auth\AuthLogic;
use think\facade\Config;
use think\facade\Log;
@@ -122,6 +123,12 @@ class PrescriptionLogic
return true;
}
// 有业务订单详情权限的用户可以查看关联处方(只读)
$perms = AuthLogic::getAuthByAdminId($adminId);
if (in_array('tcm.prescriptionOrder/detail', $perms, true)) {
return true;
}
return false;
}
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace app\adminapi\logic\tcm;
use app\adminapi\logic\stats\YejiStatsLogic;
use app\adminapi\logic\auth\AuthLogic;
use app\adminapi\logic\order\OrderLogic;
use app\common\model\Order;
@@ -323,7 +324,16 @@ class PrescriptionOrderLogic
if ($payOrderIds === []) {
return '未关联支付单,关联支付单总金额须大于等于定金门槛 ¥' . $min;
}
// 豁免权:关联的支付单中有豁免单则跳过金额校验
$hasExempt = Order::whereIn('id', $payOrderIds)
->whereNull('delete_time')
->where('is_exempt', 1)
->count();
if ($hasExempt > 0) {
return null;
}
// 检查关联支付单的总金额
$rows = Order::whereIn('id', $payOrderIds)->whereNull('delete_time')->column('amount', 'id');
$totalAmount = 0.0;
@@ -503,7 +513,7 @@ class PrescriptionOrderLogic
return [];
}
$rows = Order::whereIn('id', $ids)->whereNull('delete_time')
->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark'])
->field(['id', 'order_no', 'order_type', 'amount', 'status', 'create_time', 'creator_id', 'remark', 'is_exempt'])
->order('id', 'asc')
->select()
->toArray();
@@ -1049,11 +1059,13 @@ class PrescriptionOrderLogic
}
/**
* 业务订单列表行批量附加 linked_appointment(解析规则与详情一致:优先处方 appointment_id,否则诊单最近一条预约
* 业务订单列表行批量附加 linked_appointment(解析规则与详情一致:优先处方 appointment_id,否则诊单最近一条预约
* 业绩侧栏且带 channel_code 时优先展示与渠道收窄同源的已完成挂号,避免列表行属自媒体2Q 但展示关联为自媒体1
*
* @param array<int, array<string, mixed>> $lists
* @param array<string, mixed> $listsParams PrescriptionOrderLists 请求参数(可选)
*/
public static function appendLinkedAppointmentsToListRows(array &$lists): void
public static function appendLinkedAppointmentsToListRows(array &$lists, array $listsParams = []): void
{
if ($lists === []) {
return;
@@ -1063,6 +1075,23 @@ class PrescriptionOrderLogic
}
unset($item);
$yejiChannelHighlightByDiag = [];
if (
(int) ($listsParams['yeji_order_drawer'] ?? 0) === 1
&& trim((string) ($listsParams['channel_code'] ?? '')) !== ''
) {
$allDiagIdsForYeji = array_values(array_unique(array_filter(
array_map(static fn ($x): int => (int) ($x['diagnosis_id'] ?? 0), $lists),
static fn (int $id): bool => $id > 0
)));
if ($allDiagIdsForYeji !== []) {
$yejiChannelHighlightByDiag = YejiStatsLogic::batchResolveYejiChannelDrawerHighlightAppointmentIds(
$allDiagIdsForYeji,
$listsParams
);
}
}
$rxIds = array_values(array_unique(array_filter(array_map(
static fn ($x) => (int) ($x['prescription_id'] ?? 0),
$lists
@@ -1113,6 +1142,10 @@ class PrescriptionOrderLogic
if ($resolved <= 0 && $dgId > 0) {
$resolved = (int) ($latestApptByDiag[$dgId] ?? 0);
}
$preferredYeji = $dgId > 0 ? (int) ($yejiChannelHighlightByDiag[$dgId] ?? 0) : 0;
if ($preferredYeji > 0) {
$resolved = $preferredYeji;
}
if ($resolved > 0) {
$resolvedPairs[$idx] = [$resolved, $rxApptId];
}
@@ -25,6 +25,7 @@ class AppointmentValidate extends BaseValidate
'appointment_time' => 'require',
'appointment_type' => 'in:video,text,phone',
'channel_source' => 'require',
'channel_source_detail' => 'max:128',
'note_id' => 'require|integer',
'image_type' => 'require|in:tongue_images,report_files',
'image_path' => 'require',
@@ -44,6 +45,7 @@ class AppointmentValidate extends BaseValidate
'appointment_time' => '预约时间',
'appointment_type' => '预约类型',
'channel_source' => '渠道来源',
'channel_source_detail' => '渠道补充说明',
];
/**
@@ -52,7 +54,7 @@ class AppointmentValidate extends BaseValidate
*/
public function sceneCreate()
{
return $this->only(['patient_id', 'doctor_id', 'appointment_date', 'period', 'appointment_time', 'appointment_type', 'channel_source']);
return $this->only(['patient_id', 'doctor_id', 'appointment_date', 'period', 'appointment_time', 'appointment_type', 'channel_source', 'channel_source_detail']);
}
/**
@@ -0,0 +1,7 @@
-- 二诊医助:新指派患者已读标记
ALTER TABLE `zyt_tcm_diagnosis`
ADD COLUMN `assign_read_at` int(10) unsigned DEFAULT NULL
COMMENT '医助查看指派时间戳,NULL 未读(新指派红旗)' AFTER `assistant_id`;
-- 已有数据标记为已读,避免全部显示红旗
UPDATE `zyt_tcm_diagnosis` SET `assign_read_at` = UNIX_TIMESTAMP() WHERE `assistant_id` > 0;
@@ -0,0 +1,13 @@
-- 支付单:设置/取消豁免权(权限节点)
SET @order_menu_id := (SELECT id FROM zyt_system_menu WHERE perms = 'order.order/lists' LIMIT 1);
INSERT INTO zyt_system_menu (
pid, type, name, icon, sort, perms, paths, component,
selected, params, is_cache, is_show, is_disable, create_time, update_time
)
SELECT
@order_menu_id, 'A', '设置豁免权', '', 0, 'order.order/setExempt', '', '',
'', '', 0, 1, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
FROM DUAL
WHERE @order_menu_id IS NOT NULL
AND NOT EXISTS (SELECT 1 FROM zyt_system_menu WHERE perms = 'order.order/setExempt');
@@ -0,0 +1,3 @@
ALTER TABLE `zyt_order`
ADD COLUMN `is_exempt` tinyint(1) unsigned NOT NULL DEFAULT 0
COMMENT '豁免权:1=关联此单时跳过定金门槛校验' AFTER `status`;
@@ -1 +1 @@
import r from"./error-v6z53F3Y.js";import{f as p,ak as i,I as m,a as e,aN as s,J as o}from"./@vue/runtime-core-tF_2qJHK.js";import"./element-plus-NSC30APV.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@vue/reactivity-BmZ-20sQ.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./vue-router-BjeWxBI0.js";import"./index-CwtlLwRh.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const a="/admin/assets/no_perms-jDxcYpYC.png",n={class:"error404"},W=p({__name:"403",setup(c){return(_,t)=>(i(),m("div",n,[e(r,{code:"403",title:"您的账号权限不足,请联系管理员添加权限!","show-btn":!1},{content:s(()=>[...t[0]||(t[0]=[o("div",{class:"flex justify-center"},[o("img",{class:"w-[150px] h-[150px]",src:a,alt:""})],-1)])]),_:1})]))}});export{W as default};
import r from"./error-xZPNbzUl.js";import{f as p,ak as i,I as m,a as e,aN as s,J as o}from"./@vue/runtime-core-C6bnekPw.js";import"./element-plus-FSf94q2-.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./vue-router-QlpZ4wdW.js";import"./index-CLwyu9dm.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const a="/admin/assets/no_perms-jDxcYpYC.png",n={class:"error404"},W=p({__name:"403",setup(c){return(_,t)=>(i(),m("div",n,[e(r,{code:"403",title:"您的账号权限不足,请联系管理员添加权限!","show-btn":!1},{content:s(()=>[...t[0]||(t[0]=[o("div",{class:"flex justify-center"},[o("img",{class:"w-[150px] h-[150px]",src:a,alt:""})],-1)])]),_:1})]))}});export{W as default};
@@ -1 +1 @@
import o from"./error-v6z53F3Y.js";import{f as r,ak as t,I as m,a as p}from"./@vue/runtime-core-tF_2qJHK.js";import"./element-plus-NSC30APV.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@vue/reactivity-BmZ-20sQ.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./vue-router-BjeWxBI0.js";import"./index-CwtlLwRh.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const i={class:"error404"},T=r({__name:"404",setup(e){return(a,s)=>(t(),m("div",i,[p(o,{code:"404",title:"哎呀,出错了!您访问的页面不存在…"})]))}});export{T as default};
import o from"./error-xZPNbzUl.js";import{f as r,ak as t,I as m,a as p}from"./@vue/runtime-core-C6bnekPw.js";import"./element-plus-FSf94q2-.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./vue-router-QlpZ4wdW.js";import"./index-CLwyu9dm.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const i={class:"error404"},T=r({__name:"404",setup(e){return(a,s)=>(t(),m("div",i,[p(o,{code:"404",title:"哎呀,出错了!您访问的页面不存在…"})]))}});export{T as default};
@@ -1 +1 @@
import{H as u}from"../highlight.js-Bxt7hFFy.js";import{f as c,i as g,w as s,A as n}from"../@vue/runtime-core-tF_2qJHK.js";import{n as h}from"../@vue/reactivity-BmZ-20sQ.js";var i=c({props:{code:{type:String,required:!0},language:{type:String,default:""},autodetect:{type:Boolean,default:!0},ignoreIllegals:{type:Boolean,default:!0}},setup:function(e){var t=h(e.language);s((function(){return e.language}),(function(a){t.value=a}));var r=n((function(){return e.autodetect||!t.value})),o=n((function(){return!r.value&&!u.getLanguage(t.value)}));return{className:n((function(){return o.value?"":"hljs "+t.value})),highlightedCode:n((function(){var a;if(o.value)return console.warn('The language "'+t.value+'" you specified could not be found.'),e.code.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;");if(r.value){var l=u.highlightAuto(e.code);return t.value=(a=l.language)!==null&&a!==void 0?a:"",l.value}return(l=u.highlight(e.code,{language:t.value,ignoreIllegals:e.ignoreIllegals})).value}))}},render:function(){return g("pre",{},[g("code",{class:this.className,innerHTML:this.highlightedCode})])}}),v={install:function(e){e.component("highlightjs",i)},component:i};export{v as o};
import{H as u}from"../highlight.js-Bxt7hFFy.js";import{f as c,i as g,w as s,A as n}from"../@vue/runtime-core-C6bnekPw.js";import{n as h}from"../@vue/reactivity-DiY1c2vO.js";var i=c({props:{code:{type:String,required:!0},language:{type:String,default:""},autodetect:{type:Boolean,default:!0},ignoreIllegals:{type:Boolean,default:!0}},setup:function(e){var t=h(e.language);s((function(){return e.language}),(function(a){t.value=a}));var r=n((function(){return e.autodetect||!t.value})),o=n((function(){return!r.value&&!u.getLanguage(t.value)}));return{className:n((function(){return o.value?"":"hljs "+t.value})),highlightedCode:n((function(){var a;if(o.value)return console.warn('The language "'+t.value+'" you specified could not be found.'),e.code.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;");if(r.value){var l=u.highlightAuto(e.code);return t.value=(a=l.language)!==null&&a!==void 0?a:"",l.value}return(l=u.highlight(e.code,{language:t.value,ignoreIllegals:e.ignoreIllegals})).value}))}},render:function(){return g("pre",{},[g("code",{class:this.className,innerHTML:this.highlightedCode})])}}),v={install:function(e){e.component("highlightjs",i)},component:i};export{v as o};
@@ -1 +1 @@
import"./uikit-base-component-vue3-CTQKyL8o.js";import{A as r}from"../tuikit-atomicx-vue3-Bf7F3z1j.js";import{f as s,ak as c,I as l,aq as m,G as u,at as i,H as p,A as d}from"../@vue/runtime-core-tF_2qJHK.js";import{y as v}from"../@vue/reactivity-BmZ-20sQ.js";import"./chat-uikit-engine-zx802ozq.js";const _=(t,o)=>{const a=t.__vccOpts||t;for(const[e,n]of o)a[e]=n;return a},f={key:0,class:"chat"},h=s({name:"Chat",__name:"Chat",props:{PlaceholderEmpty:{default:null}},setup(t){const{activeConversation:o}=r(),a=d(()=>{var e;return!((e=o.value)!=null&&e.conversationID)});return(e,n)=>v(o)?(c(),l("div",f,[m(e.$slots,"default",{},void 0,!0)])):a.value&&t.PlaceholderEmpty?(c(),u(i(t.PlaceholderEmpty),{key:1})):p("",!0)}}),A=_(h,[["__scopeId","data-v-1c9c77cd"]]);typeof window<"u"&&(window.__CHAT_ATOMICX_VUE3__={name:"@tencentcloud/chat-uikit-vue3",version:"4.5.4"},console.log("[@tencentcloud/chat-uikit-vue3] v4.5.4"));export{A as E};
import"./uikit-base-component-vue3-YgTqL4da.js";import{A as r}from"../tuikit-atomicx-vue3-Dln8Zi6e.js";import{f as s,ak as c,I as l,aq as m,G as u,at as i,H as p,A as d}from"../@vue/runtime-core-C6bnekPw.js";import{y as v}from"../@vue/reactivity-DiY1c2vO.js";import"./chat-uikit-engine-zx802ozq.js";const _=(t,o)=>{const a=t.__vccOpts||t;for(const[e,n]of o)a[e]=n;return a},f={key:0,class:"chat"},h=s({name:"Chat",__name:"Chat",props:{PlaceholderEmpty:{default:null}},setup(t){const{activeConversation:o}=r(),a=d(()=>{var e;return!((e=o.value)!=null&&e.conversationID)});return(e,n)=>v(o)?(c(),l("div",f,[m(e.$slots,"default",{},void 0,!0)])):a.value&&t.PlaceholderEmpty?(c(),u(i(t.PlaceholderEmpty),{key:1})):p("",!0)}}),A=_(h,[["__scopeId","data-v-1c9c77cd"]]);typeof window<"u"&&(window.__CHAT_ATOMICX_VUE3__={name:"@tencentcloud/chat-uikit-vue3",version:"4.5.4"},console.log("[@tencentcloud/chat-uikit-vue3] v4.5.4"));export{A as E};
@@ -1,4 +1,4 @@
import{g as Ue}from"../lodash-D3kF6u-c.js";import{c as Ut,B as jt,n as rt,a as at,o as Wt,q as zt,b as qt,w as Gt,d as kt,e as Xt,f as Jt,g as B,F as ct,S as Qt,h as Yt,i as Zt,j as te,u as ee,k as se,l as ne,s as Z,r as tt,C as je,D as We,E as ze,m as qe,K as Ge,p as ke,T as Xe,t as Je,v as Qe,x as Ye,y as Ze,z as ts,A as es,G as ss,H as ns,I as os,J as is,L as rs,M as as,N as cs,O as ls,P as fs,Q as us,R as ps,U as ds,V as hs,W as ms,X as gs,Y as _s,Z as Ss,_ as bs,$ as Cs,a0 as ys,a1 as vs,a2 as Ts,a3 as ws,a4 as Es,a5 as As,a6 as Rs,a7 as Ps,a8 as Ms,a9 as Ns,aa as xs,ab as Os,ac as Vs,ad as Ds,ae as Ls,af as Is,ag as Bs,ah as Hs,ai as $s,aj as Fs,ak as Ks,al as Us,am as js,an as Ws,ao as zs,ap as qs,aq as Gs,ar as ks,as as Xs,at as Js,au as Qs,av as Ys,aw as Zs,ax as tn,ay as en,az as sn,aA as nn,aB as on,aC as rn,aD as an,aE as cn,aF as ln,aG as fn,aH as un,aI as pn,aJ as dn,aK as hn,aL as mn,aM as gn,aN as _n,aO as Sn,aP as bn,aQ as Cn,aR as yn}from"./runtime-core-tF_2qJHK.js";import{j as oe,n as L,C as v,e as T,h as vn,z as M,l as ie,s as Tn,D as wn,E as X,N as En,i as g,K as q,k as H,F as I,A as lt,I as et,L as re,f as An,M as Rn,O as Pn,u as Mn,G as ae,a as Nn,o as xn,P as On,p as Vn,Q as Dn,B as Ln}from"./shared-mAAVTE9n.js";import{y as ce,t as le,E as In,R as Bn,T as Hn,z as $n,q as Fn,A as Kn,B as Un,C as jn,D as Wn,i as zn,o as qn,x as Gn,a as kn,v as Xn,m as Jn,F as Qn,G as Yn,p as Zn,r as to,H as eo,n as so,s as no,c as oo,u as io,I as ro,J as ao,K as co,L as lo,M as fo}from"./reactivity-BmZ-20sQ.js";/**
import{g as Ue}from"../lodash-D3kF6u-c.js";import{c as Ut,B as jt,n as rt,a as at,o as Wt,q as zt,b as qt,w as Gt,d as kt,e as Xt,f as Jt,g as B,F as ct,S as Qt,h as Yt,i as Zt,j as te,u as ee,k as se,l as ne,s as Z,r as tt,C as je,D as We,E as ze,m as qe,K as Ge,p as ke,T as Xe,t as Je,v as Qe,x as Ye,y as Ze,z as ts,A as es,G as ss,H as ns,I as os,J as is,L as rs,M as as,N as cs,O as ls,P as fs,Q as us,R as ps,U as ds,V as hs,W as ms,X as gs,Y as _s,Z as Ss,_ as bs,$ as Cs,a0 as ys,a1 as vs,a2 as Ts,a3 as ws,a4 as Es,a5 as As,a6 as Rs,a7 as Ps,a8 as Ms,a9 as Ns,aa as xs,ab as Os,ac as Vs,ad as Ds,ae as Ls,af as Is,ag as Bs,ah as Hs,ai as $s,aj as Fs,ak as Ks,al as Us,am as js,an as Ws,ao as zs,ap as qs,aq as Gs,ar as ks,as as Xs,at as Js,au as Qs,av as Ys,aw as Zs,ax as tn,ay as en,az as sn,aA as nn,aB as on,aC as rn,aD as an,aE as cn,aF as ln,aG as fn,aH as un,aI as pn,aJ as dn,aK as hn,aL as mn,aM as gn,aN as _n,aO as Sn,aP as bn,aQ as Cn,aR as yn}from"./runtime-core-C6bnekPw.js";import{j as oe,n as L,C as v,e as T,h as vn,z as M,l as ie,s as Tn,D as wn,E as X,N as En,i as g,K as q,k as H,F as I,A as lt,I as et,L as re,f as An,M as Rn,O as Pn,u as Mn,G as ae,a as Nn,o as xn,P as On,p as Vn,Q as Dn,B as Ln}from"./shared-mAAVTE9n.js";import{y as ce,t as le,E as In,R as Bn,T as Hn,z as $n,u as Fn,A as Kn,B as Un,C as jn,D as Wn,i as zn,o as qn,x as Gn,a as kn,v as Xn,m as Jn,F as Qn,G as Yn,p as Zn,r as to,H as eo,n as so,s as no,c as oo,q as io,I as ro,J as ao,K as co,L as lo,M as fo}from"./reactivity-DiY1c2vO.js";/**
* @vue/runtime-dom v3.5.29
* (c) 2018-present Yuxi (Evan) You and Vue contributors
* @license MIT
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{C as A,F as C,a as w,L as h,u as D,J as R,H as g,q as k,n as W}from"../@vue/reactivity-BmZ-20sQ.js";import{w as b,b as x,n as L,g as F,$ as M,a5 as P}from"../@vue/runtime-core-tF_2qJHK.js";function J(e){return A()?(C(e),!0):!1}const d=new WeakMap,z=(...e)=>{var t;const r=e[0],n=(t=F())==null?void 0:t.proxy;if(n==null&&!M())throw new Error("injectLocal must be called in setup");return n&&d.has(n)&&r in d.get(n)?d.get(n)[r]:P(...e)},B=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const K=e=>typeof e<"u",I=Object.prototype.toString,Q=e=>I.call(e)==="[object Object]",m=()=>{};function j(e,t){function r(...n){return new Promise((a,o)=>{Promise.resolve(e(()=>t.apply(this,n),{fn:t,thisArg:this,args:n})).then(a).catch(o)})}return r}const S=e=>e();function V(...e){let t=0,r,n=!0,a=m,o,s,i,u,c;!w(e[0])&&typeof e[0]=="object"?{delay:s,trailing:i=!0,leading:u=!0,rejectOnCancel:c=!1}=e[0]:[s,i=!0,u=!0,c=!1]=e;const f=()=>{r&&(clearTimeout(r),r=void 0,a(),a=m)};return O=>{const l=h(s),v=Date.now()-t,p=()=>o=O();return f(),l<=0?(t=Date.now(),p()):(v>l&&(u||!n)?(t=Date.now(),p()):i&&(o=new Promise((y,T)=>{a=c?T:y,r=setTimeout(()=>{t=Date.now(),n=!0,y(p()),f()},Math.max(0,l-v))})),!u&&!r&&(r=setTimeout(()=>n=!0,l)),n=!1,o)}}function E(e=S,t={}){const{initialState:r="active"}=t,n=N(r==="active");function a(){n.value=!1}function o(){n.value=!0}const s=(...i)=>{n.value&&e(...i)};return{isActive:g(n),pause:a,resume:o,eventFilter:s}}function U(e){return e.endsWith("rem")?Number.parseFloat(e)*16:Number.parseFloat(e)}function G(e){return F()}function X(e){return Array.isArray(e)?e:[e]}function N(...e){if(e.length!==1)return R(...e);const t=e[0];return typeof t=="function"?g(k(()=>({get:t,set:m}))):W(t)}function Y(e,t=200,r=!1,n=!0,a=!1){return j(V(t,r,n,a),e)}function _(e,t,r={}){const{eventFilter:n=S,...a}=r;return b(e,j(n,t),a)}function Z(e,t,r={}){const{eventFilter:n,initialState:a="active",...o}=r,{eventFilter:s,pause:i,resume:u,isActive:c}=E(n,{initialState:a});return{stop:_(e,t,{...o,eventFilter:s}),pause:i,resume:u,isActive:c}}function ee(e,t=!0,r){G()?x(e,r):t?e():L(e)}function te(e=!1,t={}){const{truthyValue:r=!0,falsyValue:n=!1}=t,a=w(e),o=D(e);function s(i){if(arguments.length)return o.value=i,o.value;{const u=h(r);return o.value=o.value===u?h(n):u,o.value}}return a?s:[o,s]}function ne(e,t,r){return b(e,t,{...r,immediate:!0})}export{N as a,ee as b,Q as c,X as d,Z as e,z as f,K as g,Y as h,B as i,U as p,J as t,te as u,ne as w};
import{C as A,F as C,a as w,L as h,q as D,J as R,H as g,u as k,n as W}from"../@vue/reactivity-DiY1c2vO.js";import{w as b,b as x,n as L,g as F,$ as M,a5 as P}from"../@vue/runtime-core-C6bnekPw.js";function J(e){return A()?(C(e),!0):!1}const d=new WeakMap,z=(...e)=>{var t;const r=e[0],n=(t=F())==null?void 0:t.proxy;if(n==null&&!M())throw new Error("injectLocal must be called in setup");return n&&d.has(n)&&r in d.get(n)?d.get(n)[r]:P(...e)},B=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const K=e=>typeof e<"u",I=Object.prototype.toString,Q=e=>I.call(e)==="[object Object]",m=()=>{};function j(e,t){function r(...n){return new Promise((a,o)=>{Promise.resolve(e(()=>t.apply(this,n),{fn:t,thisArg:this,args:n})).then(a).catch(o)})}return r}const S=e=>e();function V(...e){let t=0,r,n=!0,a=m,o,s,i,u,c;!w(e[0])&&typeof e[0]=="object"?{delay:s,trailing:i=!0,leading:u=!0,rejectOnCancel:c=!1}=e[0]:[s,i=!0,u=!0,c=!1]=e;const f=()=>{r&&(clearTimeout(r),r=void 0,a(),a=m)};return O=>{const l=h(s),v=Date.now()-t,p=()=>o=O();return f(),l<=0?(t=Date.now(),p()):(v>l&&(u||!n)?(t=Date.now(),p()):i&&(o=new Promise((y,T)=>{a=c?T:y,r=setTimeout(()=>{t=Date.now(),n=!0,y(p()),f()},Math.max(0,l-v))})),!u&&!r&&(r=setTimeout(()=>n=!0,l)),n=!1,o)}}function E(e=S,t={}){const{initialState:r="active"}=t,n=N(r==="active");function a(){n.value=!1}function o(){n.value=!0}const s=(...i)=>{n.value&&e(...i)};return{isActive:g(n),pause:a,resume:o,eventFilter:s}}function U(e){return e.endsWith("rem")?Number.parseFloat(e)*16:Number.parseFloat(e)}function G(e){return F()}function X(e){return Array.isArray(e)?e:[e]}function N(...e){if(e.length!==1)return R(...e);const t=e[0];return typeof t=="function"?g(k(()=>({get:t,set:m}))):W(t)}function Y(e,t=200,r=!1,n=!0,a=!1){return j(V(t,r,n,a),e)}function _(e,t,r={}){const{eventFilter:n=S,...a}=r;return b(e,j(n,t),a)}function Z(e,t,r={}){const{eventFilter:n,initialState:a="active",...o}=r,{eventFilter:s,pause:i,resume:u,isActive:c}=E(n,{initialState:a});return{stop:_(e,t,{...o,eventFilter:s}),pause:i,resume:u,isActive:c}}function ee(e,t=!0,r){G()?x(e,r):t?e():L(e)}function te(e=!1,t={}){const{truthyValue:r=!0,falsyValue:n=!1}=t,a=w(e),o=D(e);function s(i){if(arguments.length)return o.value=i,o.value;{const u=h(r);return o.value=o.value===u?h(n):u,o.value}}return a?s:[o,s]}function ne(e,t,r){return b(e,t,{...r,immediate:!0})}export{N as a,ee as b,Q as c,X as d,Z as e,z as f,K as g,Y as h,B as i,U as p,J as t,te as u,ne as w};
@@ -1,2 +1,2 @@
import{i as C,Q as y,a as E}from"./editor-Cyf37SuL.js";import{ak as g,I as h,f as w,b as P,w as O,aJ as b}from"../@vue/runtime-core-tF_2qJHK.js";import{n as d,t as $,u as F}from"../@vue/reactivity-BmZ-20sQ.js";var B=Object.defineProperty,D=Object.defineProperties,j=Object.getOwnPropertyDescriptors,m=Object.getOwnPropertySymbols,H=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable,_=(e,t,o)=>t in e?B(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,A=(e,t)=>{for(var o in t||(t={}))H.call(t,o)&&_(e,o,t[o]);if(m)for(var o of m(t))S.call(t,o)&&_(e,o,t[o]);return e},M=(e,t)=>D(e,j(t));function u(e){let t=`请使用 '@${e}' 事件,不要放在 props 中`;return t+=`
Please use '@${e}' event instead of props`,t}var v=(e,t)=>{for(const[o,a]of t)e[o]=a;return e};const V=w({props:{mode:{type:String,default:"default"},defaultContent:{type:Array,default:[]},defaultHtml:{type:String,default:""},defaultConfig:{type:Object,default:{}},modelValue:{type:String,default:""}},setup(e,t){const o=d(null),a=F(null),i=d(""),s=()=>{if(!o.value)return;const f=$(e.defaultContent);C({selector:o.value,mode:e.mode,content:f||[],html:e.defaultHtml||e.modelValue||"",config:M(A({},e.defaultConfig),{onCreated(r){if(a.value=r,t.emit("onCreated",r),e.defaultConfig.onCreated){const n=u("onCreated");throw new Error(n)}},onChange(r){const n=r.getHtml();if(i.value=n,t.emit("update:modelValue",n),t.emit("onChange",r),e.defaultConfig.onChange){const l=u("onChange");throw new Error(l)}},onDestroyed(r){if(t.emit("onDestroyed",r),e.defaultConfig.onDestroyed){const n=u("onDestroyed");throw new Error(n)}},onMaxLength(r){if(t.emit("onMaxLength",r),e.defaultConfig.onMaxLength){const n=u("onMaxLength");throw new Error(n)}},onFocus(r){if(t.emit("onFocus",r),e.defaultConfig.onFocus){const n=u("onFocus");throw new Error(n)}},onBlur(r){if(t.emit("onBlur",r),e.defaultConfig.onBlur){const n=u("onBlur");throw new Error(n)}},customAlert(r,n){if(t.emit("customAlert",r,n),e.defaultConfig.customAlert){const l=u("customAlert");throw new Error(l)}},customPaste:(r,n)=>{if(e.defaultConfig.customPaste){const c=u("customPaste");throw new Error(c)}let l;return t.emit("customPaste",r,n,c=>{l=c}),l}})})};function p(f){const r=a.value;r!=null&&r.setHtml(f)}return P(()=>{s()}),O(()=>e.modelValue,f=>{f!==i.value&&p(f)}),{box:o}}}),I={ref:"box",style:{height:"100%"}};function L(e,t,o,a,i,s){return g(),h("div",I,null,512)}var N=v(V,[["render",L]]);const T=w({props:{editor:{type:Object},mode:{type:String,default:"default"},defaultConfig:{type:Object,default:{}}},setup(e){const t=d(null),o=a=>{if(t.value){if(a==null)throw new Error("Not found instance of Editor when create <Toolbar/> component");y.getToolbar(a)||E({editor:a,selector:t.value||"<div></div>",mode:e.mode,config:e.defaultConfig})}};return b(()=>{const{editor:a}=e;a!=null&&o(a)}),{selector:t}}}),R={ref:"selector"};function k(e,t,o,a,i,s){return g(),h("div",R,null,512)}var q=v(T,[["render",k]]);export{N as E,q as T};
import{i as C,Q as y,a as E}from"./editor-Cyf37SuL.js";import{ak as g,I as h,f as w,b as P,w as O,aJ as b}from"../@vue/runtime-core-C6bnekPw.js";import{n as d,t as $,q as F}from"../@vue/reactivity-DiY1c2vO.js";var B=Object.defineProperty,D=Object.defineProperties,j=Object.getOwnPropertyDescriptors,m=Object.getOwnPropertySymbols,H=Object.prototype.hasOwnProperty,S=Object.prototype.propertyIsEnumerable,_=(e,t,o)=>t in e?B(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,A=(e,t)=>{for(var o in t||(t={}))H.call(t,o)&&_(e,o,t[o]);if(m)for(var o of m(t))S.call(t,o)&&_(e,o,t[o]);return e},M=(e,t)=>D(e,j(t));function u(e){let t=`请使用 '@${e}' 事件,不要放在 props 中`;return t+=`
Please use '@${e}' event instead of props`,t}var v=(e,t)=>{for(const[o,a]of t)e[o]=a;return e};const V=w({props:{mode:{type:String,default:"default"},defaultContent:{type:Array,default:[]},defaultHtml:{type:String,default:""},defaultConfig:{type:Object,default:{}},modelValue:{type:String,default:""}},setup(e,t){const o=d(null),a=F(null),i=d(""),s=()=>{if(!o.value)return;const f=$(e.defaultContent);C({selector:o.value,mode:e.mode,content:f||[],html:e.defaultHtml||e.modelValue||"",config:M(A({},e.defaultConfig),{onCreated(r){if(a.value=r,t.emit("onCreated",r),e.defaultConfig.onCreated){const n=u("onCreated");throw new Error(n)}},onChange(r){const n=r.getHtml();if(i.value=n,t.emit("update:modelValue",n),t.emit("onChange",r),e.defaultConfig.onChange){const l=u("onChange");throw new Error(l)}},onDestroyed(r){if(t.emit("onDestroyed",r),e.defaultConfig.onDestroyed){const n=u("onDestroyed");throw new Error(n)}},onMaxLength(r){if(t.emit("onMaxLength",r),e.defaultConfig.onMaxLength){const n=u("onMaxLength");throw new Error(n)}},onFocus(r){if(t.emit("onFocus",r),e.defaultConfig.onFocus){const n=u("onFocus");throw new Error(n)}},onBlur(r){if(t.emit("onBlur",r),e.defaultConfig.onBlur){const n=u("onBlur");throw new Error(n)}},customAlert(r,n){if(t.emit("customAlert",r,n),e.defaultConfig.customAlert){const l=u("customAlert");throw new Error(l)}},customPaste:(r,n)=>{if(e.defaultConfig.customPaste){const c=u("customPaste");throw new Error(c)}let l;return t.emit("customPaste",r,n,c=>{l=c}),l}})})};function p(f){const r=a.value;r!=null&&r.setHtml(f)}return P(()=>{s()}),O(()=>e.modelValue,f=>{f!==i.value&&p(f)}),{box:o}}}),I={ref:"box",style:{height:"100%"}};function L(e,t,o,a,i,s){return g(),h("div",I,null,512)}var J=v(V,[["render",L]]);const T=w({props:{editor:{type:Object},mode:{type:String,default:"default"},defaultConfig:{type:Object,default:{}}},setup(e){const t=d(null),o=a=>{if(t.value){if(a==null)throw new Error("Not found instance of Editor when create <Toolbar/> component");y.getToolbar(a)||E({editor:a,selector:t.value||"<div></div>",mode:e.mode,config:e.defaultConfig})}};return b(()=>{const{editor:a}=e;a!=null&&o(a)}),{selector:t}}}),R={ref:"selector"};function k(e,t,o,a,i,s){return g(),h("div",R,null,512)}var N=v(T,[["render",k]]);export{J as E,N as T};
@@ -1 +0,0 @@
.cell-stack[data-v-05090333]{display:flex;flex-direction:column;gap:2px;line-height:1.35}
@@ -0,0 +1 @@
.cell-stack[data-v-849a5abe]{display:flex;flex-direction:column;gap:2px;line-height:1.35}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{L as x,N as y,r as I,d as $,M as C}from"./element-plus-NSC30APV.js";import{a6 as D}from"./@element-plus/icons-vue-CCtJZkK4.js";import{$ as L}from"./tcm-BNagiAsz.js";import{f as T,w as P,ak as g,I as A,aP as E,G as k,aN as n,a,O as m,J as B}from"./@vue/runtime-core-tF_2qJHK.js";import{Q as p}from"./@vue/shared-mAAVTE9n.js";import{y as F,n as b}from"./@vue/reactivity-BmZ-20sQ.js";import{_ as M}from"./index-CwtlLwRh.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const V={class:"assign-log-panel"},K=T({__name:"AssignLogPanel",props:{diagnosisId:{}},setup(h,{expose:w}){const c=h,d=b(!1),_=b([]);function v(o){const e=o.related_po_creator_name;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(o.related_po_creator_id);return Number.isFinite(t)&&t>0?`ID:${t}`:"—"}function N(o){const e=o.related_po_create_time_text;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(o.related_po_create_time);if(!Number.isFinite(t)||t<=0)return"—";const i=new Date(t*1e3);if(Number.isNaN(i.getTime()))return"—";const r=s=>String(s).padStart(2,"0");return`${i.getFullYear()}-${r(i.getMonth()+1)}-${r(i.getDate())} ${r(i.getHours())}:${r(i.getMinutes())}:${r(i.getSeconds())}`}function u(o,e){const t=e==="from"?"from_assistant_name":"to_assistant_name",i=e==="from"?"from_assistant_id":"to_assistant_id",r=o[t];if(r!=null&&String(r).trim()!==""&&String(r)!=="—")return String(r);const s=Number(o[i]);return Number.isFinite(s)&&s>0?`ID:${s}`:"—"}const f=async()=>{if(c.diagnosisId){d.value=!0;try{const o=await L({id:c.diagnosisId}),e=Array.isArray(o)?o:[];_.value=e}catch(o){console.error(o),_.value=[]}finally{d.value=!1}}};return P(()=>c.diagnosisId,()=>{f()},{immediate:!0}),w({refresh:f}),(o,e)=>{const t=y,i=$,r=I,s=C,S=x;return g(),A("div",V,[E((g(),k(s,{data:_.value,border:"",stripe:"","empty-text":"暂无指派记录"},{default:n(()=>[a(t,{label:"操作时间",width:"175",prop:"create_time_text"}),a(t,{label:"原医助","min-width":"120"},{default:n(({row:l})=>[m(p(u(l,"from")),1)]),_:1}),a(t,{label:"新医助","min-width":"120"},{default:n(({row:l})=>[m(p(u(l,"to")),1)]),_:1}),a(t,{label:"快照·业务单创建人","min-width":"130","show-overflow-tooltip":""},{default:n(({row:l})=>[m(p(v(l)),1)]),_:1}),a(t,{label:"快照·业务单创建时间",width:"190"},{header:n(()=>[e[0]||(e[0]=B("span",null,"快照·业务单创建时间",-1)),a(r,{placement:"top",content:"related_po_create_time:触发本次操作的处方业务订单 create_time;与原文助一致时表示医助创建订单时间"},{default:n(()=>[a(i,{class:"assign-log-col-hint"},{default:n(()=>[a(F(D))]),_:1})]),_:1})]),default:n(({row:l})=>[m(p(N(l)),1)]),_:1}),a(t,{label:"操作人",width:"110",prop:"operator_name"}),a(t,{label:"操作账号",width:"120",prop:"operator_account","show-overflow-tooltip":""}),a(t,{label:"IP",width:"130",prop:"ip","show-overflow-tooltip":""})]),_:1},8,["data"])),[[S,d.value]])])}}}),yt=M(K,[["__scopeId","data-v-5465d5eb"]]);export{yt as default};
import{M as x,N as y,r as I,d as $,L as C}from"./element-plus-FSf94q2-.js";import{a7 as D}from"./@element-plus/icons-vue-BDOO1F0I.js";import{$ as L}from"./tcm-CZik0zOd.js";import{f as T,w as P,ak as g,I as A,aP as E,G as k,aN as n,a,O as m,J as B}from"./@vue/runtime-core-C6bnekPw.js";import{Q as p}from"./@vue/shared-mAAVTE9n.js";import{y as F,n as b}from"./@vue/reactivity-DiY1c2vO.js";import{_ as M}from"./index-CLwyu9dm.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const V={class:"assign-log-panel"},K=T({__name:"AssignLogPanel",props:{diagnosisId:{}},setup(h,{expose:w}){const c=h,d=b(!1),_=b([]);function v(o){const e=o.related_po_creator_name;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(o.related_po_creator_id);return Number.isFinite(t)&&t>0?`ID:${t}`:"—"}function N(o){const e=o.related_po_create_time_text;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(o.related_po_create_time);if(!Number.isFinite(t)||t<=0)return"—";const i=new Date(t*1e3);if(Number.isNaN(i.getTime()))return"—";const r=s=>String(s).padStart(2,"0");return`${i.getFullYear()}-${r(i.getMonth()+1)}-${r(i.getDate())} ${r(i.getHours())}:${r(i.getMinutes())}:${r(i.getSeconds())}`}function u(o,e){const t=e==="from"?"from_assistant_name":"to_assistant_name",i=e==="from"?"from_assistant_id":"to_assistant_id",r=o[t];if(r!=null&&String(r).trim()!==""&&String(r)!=="—")return String(r);const s=Number(o[i]);return Number.isFinite(s)&&s>0?`ID:${s}`:"—"}const f=async()=>{if(c.diagnosisId){d.value=!0;try{const o=await L({id:c.diagnosisId}),e=Array.isArray(o)?o:[];_.value=e}catch(o){console.error(o),_.value=[]}finally{d.value=!1}}};return P(()=>c.diagnosisId,()=>{f()},{immediate:!0}),w({refresh:f}),(o,e)=>{const t=y,i=$,r=I,s=x,S=C;return g(),A("div",V,[E((g(),k(s,{data:_.value,border:"",stripe:"","empty-text":"暂无指派记录"},{default:n(()=>[a(t,{label:"操作时间",width:"175",prop:"create_time_text"}),a(t,{label:"原医助","min-width":"120"},{default:n(({row:l})=>[m(p(u(l,"from")),1)]),_:1}),a(t,{label:"新医助","min-width":"120"},{default:n(({row:l})=>[m(p(u(l,"to")),1)]),_:1}),a(t,{label:"快照·业务单创建人","min-width":"130","show-overflow-tooltip":""},{default:n(({row:l})=>[m(p(v(l)),1)]),_:1}),a(t,{label:"快照·业务单创建时间",width:"190"},{header:n(()=>[e[0]||(e[0]=B("span",null,"快照·业务单创建时间",-1)),a(r,{placement:"top",content:"related_po_create_time:触发本次操作的处方业务订单 create_time;与原文助一致时表示医助创建订单时间"},{default:n(()=>[a(i,{class:"assign-log-col-hint"},{default:n(()=>[a(F(D))]),_:1})]),_:1})]),default:n(({row:l})=>[m(p(N(l)),1)]),_:1}),a(t,{label:"操作人",width:"110",prop:"operator_name"}),a(t,{label:"操作账号",width:"120",prop:"operator_account","show-overflow-tooltip":""}),a(t,{label:"IP",width:"130",prop:"ip","show-overflow-tooltip":""})]),_:1},8,["data"])),[[S,d.value]])])}}}),yt=M(K,[["__scopeId","data-v-5465d5eb"]]);export{yt as default};
@@ -1 +0,0 @@
.call-record-panel .call-record-toolbar[data-v-ccdd4cff]{display:flex;align-items:center;gap:12px;margin-bottom:12px}.call-record-panel .call-record-empty[data-v-ccdd4cff]{padding:28px 12px;color:var(--el-text-color-secondary);text-align:center}.call-record-panel .call-record-empty__title[data-v-ccdd4cff]{font-size:14px;color:var(--el-text-color-primary)}.call-record-panel .call-record-empty__desc[data-v-ccdd4cff]{margin-top:8px;font-size:12px;line-height:1.6}.call-record-panel .recording-list[data-v-ccdd4cff]{display:flex;flex-direction:column;gap:8px}.call-record-panel .recording-item[data-v-ccdd4cff]{display:flex;flex-direction:column;gap:6px}.call-record-panel .recording-video[data-v-ccdd4cff]{max-width:100%;max-height:180px;border-radius:4px;background:#000}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
.call-record-panel .call-record-toolbar[data-v-78d5c9e4]{display:flex;align-items:center;gap:12px;margin-bottom:12px}.call-record-panel .call-record-empty[data-v-78d5c9e4]{padding:28px 12px;color:var(--el-text-color-secondary);text-align:center}.call-record-panel .call-record-empty__title[data-v-78d5c9e4]{font-size:14px;color:var(--el-text-color-primary)}.call-record-panel .call-record-empty__desc[data-v-78d5c9e4]{margin-top:8px;font-size:12px;line-height:1.6}
@@ -1 +1 @@
import{i as L,L as T,N as V,T as D,M as z,R as M}from"./element-plus-NSC30APV.js";import{a7 as O}from"./tcm-BNagiAsz.js";import{f as P,b as F,w as R,ak as a,I as n,a as i,aN as s,O as m,H as w,aP as j,G as g,F as A,J as H}from"./@vue/runtime-core-tF_2qJHK.js";import{y as d,n as k}from"./@vue/reactivity-BmZ-20sQ.js";import{Q as c}from"./@vue/shared-mAAVTE9n.js";import{_ as G}from"./index-CwtlLwRh.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const J={class:"case-record-list"},Q={key:0,class:"mb-3 flex justify-end"},Y={key:0},q={key:1,class:"text-gray-400"},K={class:"void-detail text-xs text-gray-500 mt-1"},U=P({__name:"CaseRecordList",props:{diagnosisId:{type:Number,default:0},readOnly:{type:Boolean,default:!1}},emits:["view","openPrescription"],setup(y,{expose:x,emit:C}){const _=y,h=C,l=k([]),p=k(!1),u=async()=>{if(_.diagnosisId){p.value=!0;try{const e=await O({diagnosis_id:_.diagnosisId});l.value=Array.isArray(e)?e:[]}catch(e){console.error("获取病历记录失败:",e),l.value=[]}finally{p.value=!1}}},S=e=>{if(!e)return"";const t=new Date(e*1e3);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`},$=e=>{h("view",e)},B=()=>{h("openPrescription")};return F(()=>{u()}),R(()=>_.diagnosisId,()=>{u()}),x({refresh:u}),(e,t)=>{const b=L,r=V,v=D,E=z,N=M,I=T;return a(),n("div",J,[y.readOnly?w("",!0):(a(),n("div",Q,[i(b,{type:"primary",size:"small",onClick:B},{default:s(()=>[...t[0]||(t[0]=[m("开方",-1)])]),_:1})])),j((a(),g(E,{data:d(l),border:""},{default:s(()=>[i(r,{prop:"prescription_date",label:"就诊日期",width:"120"}),i(r,{prop:"visit_no",label:"门诊号",width:"120"}),i(r,{prop:"clinical_diagnosis",label:"临床诊断","min-width":"160","show-overflow-tooltip":""}),i(r,{label:"处方摘要","min-width":"180"},{default:s(({row:o})=>[o.herbs&&o.herbs.length?(a(),n("span",Y,c(o.herbs.slice(0,3).map(f=>`${f.name}${f.dosage}`).join("、"))+c(o.herbs.length>3?"...":""),1)):(a(),n("span",q,"—"))]),_:1}),i(r,{prop:"doctor_name",label:"医师",width:"90","show-overflow-tooltip":""}),i(r,{label:"状态",width:"140",align:"center"},{default:s(({row:o})=>[o.void_status===1?(a(),n(A,{key:0},[i(v,{type:"danger",size:"small"},{default:s(()=>[...t[1]||(t[1]=[m("已作废",-1)])]),_:1}),H("div",K,c(o.void_by_name||"—")+" "+c(S(o.void_time)),1)],64)):(a(),g(v,{key:1,type:"success",size:"small"},{default:s(()=>[...t[2]||(t[2]=[m("正常",-1)])]),_:1}))]),_:1}),i(r,{label:"操作",width:"120",fixed:"right"},{default:s(({row:o})=>[i(b,{link:"",type:"primary",size:"small",onClick:f=>$(o)},{default:s(()=>[...t[3]||(t[3]=[m(" 查看 ",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[I,d(p)]]),!d(p)&&d(l).length===0?(a(),g(N,{key:1,description:"暂无病历记录,开方后会自动显示",class:"mt-4"})):w("",!0)])}}}),zt=G(U,[["__scopeId","data-v-043d2738"]]);export{zt as default};
import{i as L,L as T,N as V,T as D,M as z,R as M}from"./element-plus-FSf94q2-.js";import{a7 as O}from"./tcm-CZik0zOd.js";import{f as P,b as F,w as R,ak as a,I as n,a as i,aN as s,O as m,H as w,aP as j,G as g,F as A,J as H}from"./@vue/runtime-core-C6bnekPw.js";import{y as d,n as k}from"./@vue/reactivity-DiY1c2vO.js";import{Q as c}from"./@vue/shared-mAAVTE9n.js";import{_ as G}from"./index-CLwyu9dm.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const J={class:"case-record-list"},Q={key:0,class:"mb-3 flex justify-end"},Y={key:0},q={key:1,class:"text-gray-400"},K={class:"void-detail text-xs text-gray-500 mt-1"},U=P({__name:"CaseRecordList",props:{diagnosisId:{type:Number,default:0},readOnly:{type:Boolean,default:!1}},emits:["view","openPrescription"],setup(y,{expose:x,emit:C}){const _=y,h=C,l=k([]),p=k(!1),u=async()=>{if(_.diagnosisId){p.value=!0;try{const e=await O({diagnosis_id:_.diagnosisId});l.value=Array.isArray(e)?e:[]}catch(e){console.error("获取病历记录失败:",e),l.value=[]}finally{p.value=!1}}},S=e=>{if(!e)return"";const t=new Date(e*1e3);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")} ${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}`},$=e=>{h("view",e)},B=()=>{h("openPrescription")};return F(()=>{u()}),R(()=>_.diagnosisId,()=>{u()}),x({refresh:u}),(e,t)=>{const b=L,r=V,v=D,E=z,N=M,I=T;return a(),n("div",J,[y.readOnly?w("",!0):(a(),n("div",Q,[i(b,{type:"primary",size:"small",onClick:B},{default:s(()=>[...t[0]||(t[0]=[m("开方",-1)])]),_:1})])),j((a(),g(E,{data:d(l),border:""},{default:s(()=>[i(r,{prop:"prescription_date",label:"就诊日期",width:"120"}),i(r,{prop:"visit_no",label:"门诊号",width:"120"}),i(r,{prop:"clinical_diagnosis",label:"临床诊断","min-width":"160","show-overflow-tooltip":""}),i(r,{label:"处方摘要","min-width":"180"},{default:s(({row:o})=>[o.herbs&&o.herbs.length?(a(),n("span",Y,c(o.herbs.slice(0,3).map(f=>`${f.name}${f.dosage}`).join("、"))+c(o.herbs.length>3?"...":""),1)):(a(),n("span",q,"—"))]),_:1}),i(r,{prop:"doctor_name",label:"医师",width:"90","show-overflow-tooltip":""}),i(r,{label:"状态",width:"140",align:"center"},{default:s(({row:o})=>[o.void_status===1?(a(),n(A,{key:0},[i(v,{type:"danger",size:"small"},{default:s(()=>[...t[1]||(t[1]=[m("已作废",-1)])]),_:1}),H("div",K,c(o.void_by_name||"—")+" "+c(S(o.void_time)),1)],64)):(a(),g(v,{key:1,type:"success",size:"small"},{default:s(()=>[...t[2]||(t[2]=[m("正常",-1)])]),_:1}))]),_:1}),i(r,{label:"操作",width:"120",fixed:"right"},{default:s(({row:o})=>[i(b,{link:"",type:"primary",size:"small",onClick:f=>$(o)},{default:s(()=>[...t[3]||(t[3]=[m(" 查看 ",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[I,d(p)]]),!d(p)&&d(l).length===0?(a(),g(N,{key:1,description:"暂无病历记录,开方后会自动显示",class:"mt-4"})):w("",!0)])}}}),zt=G(U,[["__scopeId","data-v-043d2738"]]);export{zt as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
.diagnosis-todo-list .toolbar[data-v-c136d72f]{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin-bottom:12px}.diagnosis-todo-list .todo-table[data-v-c136d72f]{width:100%}.diagnosis-todo-list .pagination-wrap[data-v-c136d72f]{margin-top:12px;display:flex;justify-content:flex-end}.diagnosis-todo-list .text-danger[data-v-c136d72f]{color:var(--el-color-danger)}.diagnosis-todo-list .text-muted[data-v-c136d72f]{color:var(--el-text-color-placeholder)}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
.diagnosis-todo-list .toolbar[data-v-f319b354]{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin-bottom:12px}.diagnosis-todo-list .todo-table[data-v-f319b354]{width:100%}.diagnosis-todo-list .pagination-wrap[data-v-f319b354]{margin-top:12px;display:flex;justify-content:flex-end}.diagnosis-todo-list .text-danger[data-v-f319b354]{color:var(--el-color-danger)}.diagnosis-todo-list .text-muted[data-v-f319b354]{color:var(--el-text-color-placeholder)}
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
import{v as W,d as Z,R as q,a as K}from"./element-plus-NSC30APV.js";import{_ as Y}from"./picker-Z4o1kfTj.js";import{e as ee,c as te,i as S,_ as ie}from"./index-CwtlLwRh.js";import{s as A}from"./@vue/runtime-dom-CEiKlVMn.js";import{b as B,G as se}from"./@element-plus/icons-vue-CCtJZkK4.js";import{a as R,d as oe}from"./patient-D0BwU5eh.js";import{f as ne,w as re,ak as i,I as n,a as l,aN as c,J as a,H as d,F as v,ap as k,G as I}from"./@vue/runtime-core-tF_2qJHK.js";import{n as w,y as C}from"./@vue/reactivity-BmZ-20sQ.js";import{Q as z}from"./@vue/shared-mAAVTE9n.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./lodash-D3kF6u-c.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-CgAEaJvF.js";import"./index-DOquUsOX.js";import"./index.vue_vue_type_script_setup_true_lang-D53L8u8U.js";import"./index-LZuIxEs_.js";import"./index-CFOWc_EU.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-ByJn2Em4.js";import"./index.vue_vue_type_script_setup_true_lang-DXsNLQSJ.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./usePaging-BIG1oWvJ.js";import"./vuedraggable-Bl4C18MR.js";import"./vue-BEnQNo4t.js";import"./@vue/compiler-dom-CqayqxS7.js";import"./@vue/compiler-core-CvbQOXIO.js";import"./sortablejs-dsEAUXlE.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const le={class:"note-timeline-wrap"},ae={key:0,class:"timeline-actions"},me={class:"upload-trigger"},de={class:"upload-trigger"},pe={key:1,class:"note-timeline"},ce={class:"timeline-date"},ue={class:"timeline-body"},ge={key:0,class:"timeline-content"},_e={key:1,class:"timeline-images"},fe={key:2,class:"timeline-images"},ve={key:0,class:"thumb-wrap"},he={key:1,class:"file-wrap"},ye=["href","title"],ke={class:"file-name"},T=8e3,Ie=ne({__name:"NoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(m,{emit:G}){const u=m,b=G,L=ee(),g=t=>L.getImageUrl(t),x=w([]),E=w([]),_=w(0),f=w(0),$=["jpg","jpeg","png","gif","bmp","webp","svg"],N=t=>{var s;const e=((s=t.split(".").pop())==null?void 0:s.toLowerCase().split("?")[0])||"";return $.includes(e)},M=t=>{var s;const e=t.split("/");return decodeURIComponent(((s=e[e.length-1])==null?void 0:s.split("?")[0])||"文件")},j=t=>t.filter(N).map(g),O=(t,e)=>{const s=t.filter(N),h=t[e];return s.indexOf(h)},X=t=>t?t.split(`
`).filter(Boolean):[],H=t=>{if(!u.diagnosisId)return;const e=Array.isArray(t)?t:[t];if(e.length<=_.value){_.value=e.length;return}const s=e.slice(_.value);_.value=e.length,s.length>0&&R({diagnosis_id:u.diagnosisId,tongue_images:s}).then(()=>{S.msgSuccess("舌苔照片已添加"),b("refresh")})},J=t=>{if(!u.diagnosisId)return;const e=Array.isArray(t)?t:[t];if(e.length<=f.value){f.value=e.length;return}const s=e.slice(f.value);f.value=e.length,s.length>0&&R({diagnosis_id:u.diagnosisId,report_files:s}).then(()=>{S.msgSuccess("检查报告已添加"),b("refresh")})};re(()=>u.notes,()=>{x.value=[],E.value=[],_.value=0,f.value=0});const V=async(t,e,s)=>{try{await K.confirm("确认删除?","提示",{type:"warning"})}catch{return}await oe({note_id:t,image_type:e,image_path:s}),S.msgSuccess("已删除"),b("refresh")};return(t,e)=>{const s=te,h=Y,U=W,y=Z,Q=q;return i(),n("div",le,[!m.readonly&&m.diagnosisId?(i(),n("div",ae,[l(h,{modelValue:x.value,"onUpdate:modelValue":e[0]||(e[0]=o=>x.value=o),limit:99,type:"image","exclude-domain":!0,onChange:H},{upload:c(()=>[a("div",me,[l(s,{size:20,name:"el-icon-Plus"}),e[2]||(e[2]=a("span",null,"舌苔照片",-1))])]),_:1},8,["modelValue"]),l(h,{modelValue:E.value,"onUpdate:modelValue":e[1]||(e[1]=o=>E.value=o),limit:99,type:"file","exclude-domain":!0,onChange:J},{upload:c(()=>[a("div",de,[l(s,{size:20,name:"el-icon-Plus"}),e[3]||(e[3]=a("span",null,"检查报告",-1))])]),_:1},8,["modelValue"])])):d("",!0),m.notes.length?(i(),n("div",pe,[(i(!0),n(v,null,k(m.notes,o=>{var D,F;return i(),n("div",{key:o.id,class:"timeline-node"},[e[6]||(e[6]=a("div",{class:"timeline-dot"},null,-1)),a("div",ce,z(o.note_date),1),a("div",ue,[o.content?(i(),n("div",ge,[(i(!0),n(v,null,k(X(o.content),(r,p)=>(i(),n("div",{key:p,class:"content-line"},z(r),1))),128))])):d("",!0),(D=o.tongue_images)!=null&&D.length?(i(),n("div",_e,[e[4]||(e[4]=a("span",{class:"images-label"},"舌苔照片",-1)),(i(!0),n(v,null,k(o.tongue_images,(r,p)=>(i(),n("div",{key:p,class:"thumb-wrap"},[l(U,{src:g(r),"preview-src-list":o.tongue_images.map(g),"initial-index":p,"z-index":T,fit:"cover",class:"timeline-thumb","preview-teleported":""},null,8,["src","preview-src-list","initial-index"]),m.readonly?d("",!0):(i(),I(y,{key:0,class:"thumb-delete",onClick:A(P=>V(o.id,"tongue_images",r),["stop"])},{default:c(()=>[l(C(B))]),_:1},8,["onClick"]))]))),128))])):d("",!0),(F=o.report_files)!=null&&F.length?(i(),n("div",fe,[e[5]||(e[5]=a("span",{class:"images-label"},"检查报告",-1)),(i(!0),n(v,null,k(o.report_files,(r,p)=>(i(),n(v,{key:p},[N(r)?(i(),n("div",ve,[l(U,{src:g(r),"preview-src-list":j(o.report_files),"initial-index":O(o.report_files,p),"z-index":T,fit:"cover",class:"timeline-thumb","preview-teleported":""},null,8,["src","preview-src-list","initial-index"]),m.readonly?d("",!0):(i(),I(y,{key:0,class:"thumb-delete",onClick:A(P=>V(o.id,"report_files",r),["stop"])},{default:c(()=>[l(C(B))]),_:1},8,["onClick"]))])):(i(),n("div",he,[a("a",{href:g(r),target:"_blank",class:"file-link",title:M(r)},[l(y,{size:20},{default:c(()=>[l(C(se))]),_:1}),a("span",ke,z(M(r)),1)],8,ye),m.readonly?d("",!0):(i(),I(y,{key:0,class:"file-delete",onClick:A(P=>V(o.id,"report_files",r),["stop"])},{default:c(()=>[l(C(B))]),_:1},8,["onClick"]))]))],64))),128))])):d("",!0)])])}),128))])):d("",!0),!m.notes.length&&m.readonly?(i(),I(Q,{key:2,description:"暂无备注","image-size":48})):d("",!0)])}}}),It=ie(Ie,[["__scopeId","data-v-f77bb3f4"]]);export{It as default};
import{R as W,v as Z,d as q,a as K}from"./element-plus-FSf94q2-.js";import{_ as Y}from"./picker-S140y0Ck.js";import{e as ee,c as te,i as S,_ as ie}from"./index-CLwyu9dm.js";import{s as A}from"./@vue/runtime-dom-DDAG46FW.js";import{b as B,G as se}from"./@element-plus/icons-vue-BDOO1F0I.js";import{d as oe,a as R}from"./patient-DNjuO9kO.js";import{f as ne,w as re,ak as i,I as n,a as l,aN as c,J as a,H as d,F as v,ap as k,G as I}from"./@vue/runtime-core-C6bnekPw.js";import{n as w,y as C}from"./@vue/reactivity-DiY1c2vO.js";import{Q as z}from"./@vue/shared-mAAVTE9n.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./lodash-D3kF6u-c.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-CbVXHb-T.js";import"./index-Ddx1af9I.js";import"./index.vue_vue_type_script_setup_true_lang-CcHKbLKc.js";import"./index-Dn5DJbNI.js";import"./index-iCSIrF-J.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-C8XkNg4E.js";import"./index.vue_vue_type_script_setup_true_lang-zIjDr0d2.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./usePaging-VsbTxSU0.js";import"./vuedraggable-5bKFmC7X.js";import"./vue-BVs68q8v.js";import"./@vue/compiler-dom-CqayqxS7.js";import"./@vue/compiler-core-CvbQOXIO.js";import"./sortablejs-dsEAUXlE.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const le={class:"note-timeline-wrap"},ae={key:0,class:"timeline-actions"},me={class:"upload-trigger"},de={class:"upload-trigger"},pe={key:1,class:"note-timeline"},ce={class:"timeline-date"},ue={class:"timeline-body"},ge={key:0,class:"timeline-content"},_e={key:1,class:"timeline-images"},fe={key:2,class:"timeline-images"},ve={key:0,class:"thumb-wrap"},he={key:1,class:"file-wrap"},ye=["href","title"],ke={class:"file-name"},T=8e3,Ie=ne({__name:"NoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(m,{emit:G}){const u=m,b=G,L=ee(),g=t=>L.getImageUrl(t),x=w([]),E=w([]),_=w(0),f=w(0),$=["jpg","jpeg","png","gif","bmp","webp","svg"],N=t=>{var s;const e=((s=t.split(".").pop())==null?void 0:s.toLowerCase().split("?")[0])||"";return $.includes(e)},M=t=>{var s;const e=t.split("/");return decodeURIComponent(((s=e[e.length-1])==null?void 0:s.split("?")[0])||"文件")},j=t=>t.filter(N).map(g),O=(t,e)=>{const s=t.filter(N),h=t[e];return s.indexOf(h)},X=t=>t?t.split(`
`).filter(Boolean):[],H=t=>{if(!u.diagnosisId)return;const e=Array.isArray(t)?t:[t];if(e.length<=_.value){_.value=e.length;return}const s=e.slice(_.value);_.value=e.length,s.length>0&&R({diagnosis_id:u.diagnosisId,tongue_images:s}).then(()=>{S.msgSuccess("舌苔照片已添加"),b("refresh")})},J=t=>{if(!u.diagnosisId)return;const e=Array.isArray(t)?t:[t];if(e.length<=f.value){f.value=e.length;return}const s=e.slice(f.value);f.value=e.length,s.length>0&&R({diagnosis_id:u.diagnosisId,report_files:s}).then(()=>{S.msgSuccess("检查报告已添加"),b("refresh")})};re(()=>u.notes,()=>{x.value=[],E.value=[],_.value=0,f.value=0});const V=async(t,e,s)=>{try{await K.confirm("确认删除?","提示",{type:"warning"})}catch{return}await oe({note_id:t,image_type:e,image_path:s}),S.msgSuccess("已删除"),b("refresh")};return(t,e)=>{const s=te,h=Y,U=Z,y=q,Q=W;return i(),n("div",le,[!m.readonly&&m.diagnosisId?(i(),n("div",ae,[l(h,{modelValue:x.value,"onUpdate:modelValue":e[0]||(e[0]=o=>x.value=o),limit:99,type:"image","exclude-domain":!0,onChange:H},{upload:c(()=>[a("div",me,[l(s,{size:20,name:"el-icon-Plus"}),e[2]||(e[2]=a("span",null,"舌苔照片",-1))])]),_:1},8,["modelValue"]),l(h,{modelValue:E.value,"onUpdate:modelValue":e[1]||(e[1]=o=>E.value=o),limit:99,type:"file","exclude-domain":!0,onChange:J},{upload:c(()=>[a("div",de,[l(s,{size:20,name:"el-icon-Plus"}),e[3]||(e[3]=a("span",null,"检查报告",-1))])]),_:1},8,["modelValue"])])):d("",!0),m.notes.length?(i(),n("div",pe,[(i(!0),n(v,null,k(m.notes,o=>{var D,F;return i(),n("div",{key:o.id,class:"timeline-node"},[e[6]||(e[6]=a("div",{class:"timeline-dot"},null,-1)),a("div",ce,z(o.note_date),1),a("div",ue,[o.content?(i(),n("div",ge,[(i(!0),n(v,null,k(X(o.content),(r,p)=>(i(),n("div",{key:p,class:"content-line"},z(r),1))),128))])):d("",!0),(D=o.tongue_images)!=null&&D.length?(i(),n("div",_e,[e[4]||(e[4]=a("span",{class:"images-label"},"舌苔照片",-1)),(i(!0),n(v,null,k(o.tongue_images,(r,p)=>(i(),n("div",{key:p,class:"thumb-wrap"},[l(U,{src:g(r),"preview-src-list":o.tongue_images.map(g),"initial-index":p,"z-index":T,fit:"cover",class:"timeline-thumb","preview-teleported":""},null,8,["src","preview-src-list","initial-index"]),m.readonly?d("",!0):(i(),I(y,{key:0,class:"thumb-delete",onClick:A(P=>V(o.id,"tongue_images",r),["stop"])},{default:c(()=>[l(C(B))]),_:1},8,["onClick"]))]))),128))])):d("",!0),(F=o.report_files)!=null&&F.length?(i(),n("div",fe,[e[5]||(e[5]=a("span",{class:"images-label"},"检查报告",-1)),(i(!0),n(v,null,k(o.report_files,(r,p)=>(i(),n(v,{key:p},[N(r)?(i(),n("div",ve,[l(U,{src:g(r),"preview-src-list":j(o.report_files),"initial-index":O(o.report_files,p),"z-index":T,fit:"cover",class:"timeline-thumb","preview-teleported":""},null,8,["src","preview-src-list","initial-index"]),m.readonly?d("",!0):(i(),I(y,{key:0,class:"thumb-delete",onClick:A(P=>V(o.id,"report_files",r),["stop"])},{default:c(()=>[l(C(B))]),_:1},8,["onClick"]))])):(i(),n("div",he,[a("a",{href:g(r),target:"_blank",class:"file-link",title:M(r)},[l(y,{size:20},{default:c(()=>[l(C(se))]),_:1}),a("span",ke,z(M(r)),1)],8,ye),m.readonly?d("",!0):(i(),I(y,{key:0,class:"file-delete",onClick:A(P=>V(o.id,"report_files",r),["stop"])},{default:c(()=>[l(C(B))]),_:1},8,["onClick"]))]))],64))),128))])):d("",!0)])])}),128))])):d("",!0),!m.notes.length&&m.readonly?(i(),I(Q,{key:2,description:"暂无备注","image-size":48})):d("",!0)])}}}),It=ie(Ie,[["__scopeId","data-v-f77bb3f4"]]);export{It as default};
@@ -1 +1 @@
import{m as x,f as y,a as B}from"./diag-display-DCz_VAqj.js";import{f as w,ak as I,I as P,J as a,H as N}from"./@vue/runtime-core-tF_2qJHK.js";import{Q as i}from"./@vue/shared-mAAVTE9n.js";import{y as e}from"./@vue/reactivity-BmZ-20sQ.js";import{_ as V}from"./index-CwtlLwRh.js";import"./lodash-D3kF6u-c.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./element-plus-NSC30APV.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const D={class:"card patient-card"},E={class:"patient-hero"},G={class:"patient-name"},H={class:"patient-meta"},J={key:0},Q=w({__name:"PatientInfoCard",props:{apt:{default:()=>({})},diag:{default:()=>({})}},setup(t){return(S,o)=>{var m,r,n,d,p,s,c,l,g,f,u,h,v,k,C;return I(),P("div",D,[o[0]||(o[0]=a("div",{class:"card-title"},"患者信息",-1)),a("div",E,[a("div",G,i(((m=t.apt)==null?void 0:m.patient_name)||"—"),1),a("div",H,[a("div",null,i(e(x)((r=t.apt)==null?void 0:r.patient_phone))+" · "+i(e(y)((n=t.diag)==null?void 0:n.gender))+" · "+i(((d=t.diag)==null?void 0:d.age)!=null?t.diag.age+"岁":"—"),1),a("div",null,i((p=t.diag)!=null&&p.height?t.diag.height+"cm":"—")+" / "+i((s=t.diag)!=null&&s.weight?t.diag.weight+"kg":"—")+" · "+i(((c=t.diag)==null?void 0:c.region)||"—"),1),a("div",null," 预约:"+i((l=t.apt)==null?void 0:l.appointment_date)+" "+i((g=t.apt)==null?void 0:g.appointment_time)+" · "+i(e(B)((f=t.apt)==null?void 0:f.period)),1),a("div",null,"医生:"+i(((u=t.apt)==null?void 0:u.doctor_name)||"—")+" 医助:"+i(((h=t.apt)==null?void 0:h.assistant_name)||"—"),1),a("div",null," 状态:"+i(((v=t.apt)==null?void 0:v.status_desc)||"—")+" · "+i((k=t.apt)!=null&&k.has_prescription?"已开方":"未开方"),1),(C=t.apt)!=null&&C.remark?(I(),P("div",J,"备注:"+i(t.apt.remark),1)):N("",!0)])])])}}}),Ct=V(Q,[["__scopeId","data-v-e3476da5"]]);export{Ct as default};
import{m as x,f as y,a as B}from"./diag-display-DCz_VAqj.js";import{f as w,ak as I,I as P,J as a,H as N}from"./@vue/runtime-core-C6bnekPw.js";import{Q as i}from"./@vue/shared-mAAVTE9n.js";import{y as e}from"./@vue/reactivity-DiY1c2vO.js";import{_ as V}from"./index-CLwyu9dm.js";import"./lodash-D3kF6u-c.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./element-plus-FSf94q2-.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const D={class:"card patient-card"},E={class:"patient-hero"},G={class:"patient-name"},H={class:"patient-meta"},J={key:0},Q=w({__name:"PatientInfoCard",props:{apt:{default:()=>({})},diag:{default:()=>({})}},setup(t){return(S,o)=>{var m,r,n,d,p,s,c,l,g,f,u,h,v,k,C;return I(),P("div",D,[o[0]||(o[0]=a("div",{class:"card-title"},"患者信息",-1)),a("div",E,[a("div",G,i(((m=t.apt)==null?void 0:m.patient_name)||"—"),1),a("div",H,[a("div",null,i(e(x)((r=t.apt)==null?void 0:r.patient_phone))+" · "+i(e(y)((n=t.diag)==null?void 0:n.gender))+" · "+i(((d=t.diag)==null?void 0:d.age)!=null?t.diag.age+"岁":"—"),1),a("div",null,i((p=t.diag)!=null&&p.height?t.diag.height+"cm":"—")+" / "+i((s=t.diag)!=null&&s.weight?t.diag.weight+"kg":"—")+" · "+i(((c=t.diag)==null?void 0:c.region)||"—"),1),a("div",null," 预约:"+i((l=t.apt)==null?void 0:l.appointment_date)+" "+i((g=t.apt)==null?void 0:g.appointment_time)+" · "+i(e(B)((f=t.apt)==null?void 0:f.period)),1),a("div",null,"医生:"+i(((u=t.apt)==null?void 0:u.doctor_name)||"—")+" 医助:"+i(((h=t.apt)==null?void 0:h.assistant_name)||"—"),1),a("div",null," 状态:"+i(((v=t.apt)==null?void 0:v.status_desc)||"—")+" · "+i((k=t.apt)!=null&&k.has_prescription?"已开方":"未开方"),1),(C=t.apt)!=null&&C.remark?(I(),P("div",J,"备注:"+i(t.apt.remark),1)):N("",!0)])])])}}}),Ct=V(Q,[["__scopeId","data-v-e3476da5"]]);export{Ct as default};
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{R as V,L as C,N as D,T as O,M as S}from"./element-plus-NSC30APV.js";import{_ as B}from"./index.vue_vue_type_script_setup_true_lang-D53L8u8U.js";import{u as j}from"./usePaging-BIG1oWvJ.js";import{j as A}from"./tcm-BNagiAsz.js";import{f as M,w as z,ak as d,I as g,a as i,F as R,aP as q,G,aN as n,J as h,O as c,A as w}from"./@vue/runtime-core-tF_2qJHK.js";import{y as u,a as H,r as J}from"./@vue/reactivity-BmZ-20sQ.js";import{Q as p}from"./@vue/shared-mAAVTE9n.js";import{_ as Q}from"./index-CwtlLwRh.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const U={class:"patient-order-list"},Y={key:0,class:"po-empty-tip"},K={class:"text-red-500 font-semibold"},W={class:"flex justify-end mt-3"},X=M({__name:"PatientOrderList",props:{diagnosisId:{},patientId:{}},setup(y,{expose:v}){const l=y,f=w(()=>{const e=Number(l.patientId);return Number.isFinite(e)&&e>0?e:0}),_=w(()=>f.value>0),m=J({}),{pager:s,getLists:b,resetPage:x}=j({fetchFun:A,params:m,size:10}),N=()=>{Object.keys(m).forEach(e=>delete m[e]),l.diagnosisId>0&&(m.context_diagnosis_id=l.diagnosisId),_.value&&(m.patient_id=f.value),m.scene="diagnosis_edit"},I=e=>{const t=Number(e);return Number.isFinite(t)?t.toFixed(2):"0.00"},T=e=>{if(e==null||e==="")return"—";if(typeof e=="number"&&e>1e9&&e<1e11){const t=new Date(e*1e3),a=r=>String(r).padStart(2,"0");return`${t.getFullYear()}-${a(t.getMonth()+1)}-${a(t.getDate())} ${a(t.getHours())}:${a(t.getMinutes())}:${a(t.getSeconds())}`}return String(e)},k=e=>({1:"待双审通过",2:"待发货",3:"已完成",4:"已取消",5:"已发货",6:"已签收",7:"进行中",8:"暂不制药",9:"拒收",10:"退款",11:"保留药方",12:"制药缓发"})[Number(e)]??"—",E=e=>{const t=Number(e);return t===3||t===6?"success":t===5?"primary":t===4||t===9||t===10?"danger":t===2||t===7?"warning":"info"};return z(()=>[l.diagnosisId,f.value],()=>{if(!_.value){s.lists=[],s.count=0;return}N(),x()},{immediate:!0}),v({refresh:()=>b()}),(e,t)=>{const a=V,r=D,F=O,P=S,$=B,L=C;return d(),g("div",U,[_.value?(d(),g(R,{key:1},[q((d(),G(P,{data:u(s).lists,border:"",stripe:"","empty-text":"暂无业务订单"},{default:n(()=>[i(r,{label:"订单编号",prop:"order_no","min-width":"200","show-overflow-tooltip":""}),i(r,{label:"金额",width:"120",align:"right"},{default:n(({row:o})=>[h("span",K,"¥"+p(I(o.amount)),1)]),_:1}),i(r,{label:"医生",prop:"doctor_name",width:"110","show-overflow-tooltip":""},{default:n(({row:o})=>[c(p(o.doctor_name||"—"),1)]),_:1}),i(r,{label:"医助",prop:"assistant_name",width:"110","show-overflow-tooltip":""},{default:n(({row:o})=>[c(p(o.assistant_name||"—"),1)]),_:1}),i(r,{label:"履约状态",width:"110"},{default:n(({row:o})=>[i(F,{type:E(o.fulfillment_status),size:"small",effect:"light"},{default:n(()=>[c(p(k(o.fulfillment_status)),1)]),_:2},1032,["type"])]),_:1}),i(r,{label:"创建时间","min-width":"170"},{default:n(({row:o})=>[c(p(T(o.create_time)),1)]),_:1})]),_:1},8,["data"])),[[L,u(s).loading]]),h("div",W,[i($,{modelValue:u(s),"onUpdate:modelValue":t[0]||(t[0]=o=>H(s)?s.value=o:null),onChange:u(b)},null,8,["modelValue","onChange"])])],64)):(d(),g("div",Y,[i(a,{description:"当前诊单未携带患者ID,无法列出业务订单"})]))])}}}),At=Q(X,[["__scopeId","data-v-e5ebc4c4"]]);export{At as default};
@@ -1 +0,0 @@
.patient-order-list[data-v-e5ebc4c4]{padding:4px 0}.po-empty-tip[data-v-e5ebc4c4]{padding:24px 0}
@@ -0,0 +1 @@
.patient-order-list[data-v-b8d83d0c]{padding:4px 0}.po-empty-tip[data-v-b8d83d0c]{padding:24px 0}.audit-stamp[data-v-b8d83d0c]{position:absolute;top:12px;right:16px;transform:rotate(15deg);opacity:.15;pointer-events:none;z-index:1}.stamp-inner[data-v-b8d83d0c]{border:3px solid currentColor;border-radius:8px;padding:4px 12px;font-size:18px;font-weight:700}.stamp-pass[data-v-b8d83d0c]{color:#22c55e}.stamp-reject[data-v-b8d83d0c]{color:#ef4444}
@@ -0,0 +1 @@
.recording-list[data-v-d67b2e91]{display:flex;flex-direction:column;gap:8px}.recording-item[data-v-d67b2e91]{display:flex;flex-direction:column;gap:6px;transform:translateZ(0)}.recording-alternates[data-v-d67b2e91]{margin-top:4px;padding-top:8px;border-top:1px dashed var(--el-border-color-lighter)}.recording-alternates__label[data-v-d67b2e91]{display:block;margin-bottom:6px;font-size:12px;color:var(--el-text-color-secondary)}.recording-alternates__links[data-v-d67b2e91]{display:flex;flex-wrap:wrap;gap:8px 12px}.recording-alternates__link[data-v-d67b2e91]{font-size:12px}
@@ -0,0 +1 @@
import{_ as L}from"./element-plus-FSf94q2-.js";import B from"./RecordingVideoPlayer-CKvU5-RG.js";import{e as H,_ as I}from"./index-CLwyu9dm.js";import{f as w,ak as n,I as m,J as p,F as _,G as u,aN as v,O as k,H as y,ap as R,A as d}from"./@vue/runtime-core-C6bnekPw.js";import{Q as q}from"./@vue/shared-mAAVTE9n.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const C={key:0,class:"recording-list"},N={class:"recording-item"},P={key:1,class:"recording-alternates"},V={class:"recording-alternates__links"},A={key:1,class:"text-gray-400"},E=w({__name:"RecordingPlaybackBlock",props:{recordId:{},urls:{}},setup(c){const $=c,h=H(),l=d(()=>{const e=$.urls||[],t=new Set,r=[];for(const s of e){const o=String(s??"").trim();!o||t.has(o)||(t.add(o),r.push(o))}return r}),a=d(()=>{const e=l.value;if(!e.length)return null;const t=e.find(i=>/\.mp4(\?|#|$)/i.test(i));if(t)return t;const r=e.find(i=>/\.m3u8(\?|#|$)/i.test(i)&&/vod-qcloud\.com/i.test(i));if(r)return r;const s=e.find(i=>/\.m3u8(\?|#|$)/i.test(i)&&/\.cos\.[^/]+\.myqcloud\.com/i.test(i));if(s)return s;const o=e.find(i=>/\.m3u8(\?|#|$)/i.test(i));return o||e[0]}),f=d(()=>{const e=l.value,t=a.value;return t?e.filter(r=>r!==t):e.slice(1)});function b(e){if(!e||typeof e!="string")return!1;const t=e.trim();return/^https?:\/\//i.test(t)?/\.(mp4|webm|ogg|mov|mkv|m4v|m3u8)(\?|#|$)/i.test(t):/\.(mp4|webm|ogg|mov|mkv|m4v|m3u8)(\?|#|$)/i.test(t)||t.startsWith("/uploads/")}function g(e){return h.getImageUrl(String(e||"").trim())}function S(e,t){const r=e.trim();return/\.mp4(\?|#|$)/i.test(r)?`MP4 ${t+1}`:/vod-qcloud\.com/i.test(r)&&/\.m3u8/i.test(r)?`点播 ${t+1}`:/\.cos\.[^/]+\.myqcloud\.com/i.test(r)&&/\.m3u8/i.test(r)?`COS HLS ${t+1}`:/\.m3u8/i.test(r)?`HLS ${t+1}`:`链接 ${t+1}`}return(e,t)=>{const r=L;return l.value.length?(n(),m("div",C,[p("div",N,[a.value?(n(),m(_,{key:0},[b(a.value)?(n(),u(B,{key:`${c.recordId}-${a.value}`,src:a.value},null,8,["src"])):(n(),u(r,{key:1,href:g(a.value),target:"_blank",type:"primary"},{default:v(()=>[...t[0]||(t[0]=[k(" 打开回放 ",-1)])]),_:1},8,["href"]))],64)):y("",!0),f.value.length?(n(),m("div",P,[t[1]||(t[1]=p("span",{class:"recording-alternates__label"},"备用地址",-1)),p("div",V,[(n(!0),m(_,null,R(f.value,(s,o)=>(n(),u(r,{key:`${c.recordId}-alt-${o}-${s.slice(-32)}`,href:g(s),target:"_blank",type:"primary",class:"recording-alternates__link"},{default:v(()=>[k(q(S(s,o)),1)]),_:2},1032,["href"]))),128))])])):y("",!0)])])):(n(),m("span",A,"暂无"))}}}),ht=I(E,[["__scopeId","data-v-d67b2e91"]]);export{ht as default};
@@ -0,0 +1 @@
.recording-playback[data-v-749b0199]{width:100%;min-height:1px}.recording-playback__shell[data-v-749b0199]{position:relative;width:100%}.recording-video[data-v-749b0199]{display:block;width:100%;max-width:100%;max-height:180px;height:auto;aspect-ratio:16/9;-o-object-fit:contain;object-fit:contain;border-radius:4px;background:#000;transform:translateZ(0)}.recording-playback__overlay[data-v-749b0199]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:10px 12px;border-radius:4px;background:#0000009e;color:#fff;font-size:12px;line-height:1.45;text-align:center;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.recording-playback__overlay-title[data-v-749b0199]{font-weight:600}.recording-playback__overlay-desc[data-v-749b0199]{opacity:.92;font-size:11px}.recording-playback__spin[data-v-749b0199]{font-size:24px;animation:recording-spin-749b0199 .9s linear infinite}@keyframes recording-spin-749b0199{to{transform:rotate(360deg)}}.recording-playback__hint[data-v-749b0199]{margin-top:4px;font-size:12px;color:var(--el-text-color-secondary);line-height:1.4}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
import{C as I,i as V,R as w}from"./element-plus-NSC30APV.js";import{Q as T}from"./tcm-BNagiAsz.js";import{i as C,_ as E}from"./index-CwtlLwRh.js";import{f as z,ak as t,I as e,a as p,J as l,aN as H,O as S,H as m,F as c,ap as u,G as F}from"./@vue/runtime-core-tF_2qJHK.js";import{Q as f}from"./@vue/shared-mAAVTE9n.js";import{n as g}from"./@vue/reactivity-BmZ-20sQ.js";/* empty css */import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";const L={class:"tracking-timeline-wrap"},M={key:0,class:"timeline-input"},Q={class:"input-actions"},A={key:1,class:"tracking-timeline"},D={class:"timeline-date"},G={class:"timeline-body"},J={key:0,class:"timeline-content"},O=z({__name:"TrackingNoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(i,{emit:v}){const d=i,y=v,r=g(""),a=g(!1),_=o=>o?o.split(`
import{C as I,i as V,R as w}from"./element-plus-FSf94q2-.js";import{Q as T}from"./tcm-CZik0zOd.js";import{i as C,_ as E}from"./index-CLwyu9dm.js";import{f as z,ak as t,I as e,a as p,J as l,aN as H,O as S,H as m,F as c,ap as u,G as F}from"./@vue/runtime-core-C6bnekPw.js";import{Q as f}from"./@vue/shared-mAAVTE9n.js";import{n as g}from"./@vue/reactivity-DiY1c2vO.js";/* empty css */import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";const L={class:"tracking-timeline-wrap"},M={key:0,class:"timeline-input"},Q={class:"input-actions"},A={key:1,class:"tracking-timeline"},D={class:"timeline-date"},G={class:"timeline-body"},J={key:0,class:"timeline-content"},O=z({__name:"TrackingNoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(i,{emit:v}){const d=i,y=v,r=g(""),a=g(!1),_=o=>o?o.split(`
`).filter(Boolean):[],k=async()=>{if(!d.diagnosisId)return;const o=r.value.trim();if(o){a.value=!0;try{await T({diagnosis_id:d.diagnosisId,tracking_content:o}),C.msgSuccess("已添加"),r.value="",y("refresh")}finally{a.value=!1}}};return(o,n)=>{const h=I,b=V,N=w;return t(),e("div",L,[!i.readonly&&i.diagnosisId?(t(),e("div",M,[p(h,{modelValue:r.value,"onUpdate:modelValue":n[0]||(n[0]=s=>r.value=s),type:"textarea",rows:2,placeholder:"输入跟踪备注,回车换行;保存后将以「[HH:MM] 内容」追加到当天记录",maxlength:"1000","show-word-limit":"",resize:"none",disabled:a.value},null,8,["modelValue","disabled"]),l("div",Q,[p(b,{type:"primary",size:"small",loading:a.value,disabled:!r.value.trim(),onClick:k},{default:H(()=>[...n[1]||(n[1]=[S(" 添加 ",-1)])]),_:1},8,["loading","disabled"])])])):m("",!0),i.notes.length?(t(),e("div",A,[(t(!0),e(c,null,u(i.notes,s=>(t(),e("div",{key:s.id,class:"timeline-node"},[n[2]||(n[2]=l("div",{class:"timeline-dot"},null,-1)),l("div",D,f(s.note_date),1),l("div",G,[s.content?(t(),e("div",J,[(t(!0),e(c,null,u(_(s.content),(x,B)=>(t(),e("div",{key:B,class:"content-line"},f(x),1))),128))])):m("",!0)])]))),128))])):m("",!0),!i.notes.length&&i.readonly?(t(),F(N,{key:2,description:"暂无跟踪备注","image-size":48})):m("",!0)])}}}),Tt=E(O,[["__scopeId","data-v-82b635bd"]]);export{Tt as default};
@@ -1 +1 @@
import{_ as o}from"./account-adjust.vue_vue_type_script_setup_true_lang-DUS7dkYv.js";import"./element-plus-NSC30APV.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@vue/runtime-core-tF_2qJHK.js";import"./@vue/reactivity-BmZ-20sQ.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-CgAEaJvF.js";import"./index-CwtlLwRh.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";export{o as default};
import{_ as o}from"./account-adjust.vue_vue_type_script_setup_true_lang-D5b6gD4R.js";import"./element-plus-FSf94q2-.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/runtime-core-C6bnekPw.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-CbVXHb-T.js";import"./index-CLwyu9dm.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";export{o as default};
@@ -0,0 +1 @@
import{D as h,B as q,G as B,I,C as D}from"./element-plus-FSf94q2-.js";import{_ as F}from"./index-CbVXHb-T.js";import{i as b}from"./index-CLwyu9dm.js";import{f as G,w,ak as j,G as S,aN as r,J as U,a,O as u,A}from"./@vue/runtime-core-C6bnekPw.js";import{y as n,q as y,r as J}from"./@vue/reactivity-DiY1c2vO.js";import{Q as k}from"./@vue/shared-mAAVTE9n.js";const M={class:"pr-8"},L=G({__name:"account-adjust",props:{show:{type:Boolean,required:!0},value:{type:[Number,String],required:!0}},emits:["update:show","confirm"],setup(d,{emit:V}){const s=y(),i=d,f=V,o=J({action:1,num:"",remark:""}),m=y(),c=A(()=>Number(i.value)+Number(o.num)*(o.action==1?1:-1)),R={num:[{required:!0,message:"请输入调整的金额"}]},g=e=>{if(e.includes("-"))return b.msgError("请输入正整数");o.num=e},x=async()=>{var e;await((e=s.value)==null?void 0:e.validate()),f("confirm",o)},C=()=>{var e;f("update:show",!1),(e=s.value)==null||e.resetFields()};return w(()=>i.show,e=>{var t,l;e?(t=m.value)==null||t.open():(l=m.value)==null||l.close()}),w(c,e=>{e<0&&(b.msgError("调整后余额需大于0"),o.num="")}),(e,t)=>{const l=q,_=I,E=B,v=D,N=h;return j(),S(F,{ref_key:"popupRef",ref:m,title:"余额调整",width:"500px",onConfirm:x,async:!0,onClose:C},{default:r(()=>[U("div",M,[a(N,{ref_key:"formRef",ref:s,model:n(o),"label-width":"120px",rules:R},{default:r(()=>[a(l,{label:"当前余额"},{default:r(()=>[u("¥ "+k(d.value),1)]),_:1}),a(l,{label:"余额增减",required:"",prop:"action"},{default:r(()=>[a(E,{modelValue:n(o).action,"onUpdate:modelValue":t[0]||(t[0]=p=>n(o).action=p)},{default:r(()=>[a(_,{value:1},{default:r(()=>[...t[2]||(t[2]=[u("增加余额",-1)])]),_:1}),a(_,{value:2},{default:r(()=>[...t[3]||(t[3]=[u("扣减余额",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),a(l,{label:"调整余额",prop:"num"},{default:r(()=>[a(v,{"model-value":n(o).num,placeholder:"请输入调整的金额",type:"number",onInput:g},null,8,["model-value"])]),_:1}),a(l,{label:"调整后余额"},{default:r(()=>[u(" ¥ "+k(n(c)),1)]),_:1}),a(l,{label:"备注",prop:"remark"},{default:r(()=>[a(v,{modelValue:n(o).remark,"onUpdate:modelValue":t[1]||(t[1]=p=>n(o).remark=p),type:"textarea",rows:4},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])])]),_:1},512)}}});export{L as _};
@@ -1 +0,0 @@
import{D as h,B,G as q,I,C as D}from"./element-plus-NSC30APV.js";import{_ as F}from"./index-CgAEaJvF.js";import{i as b}from"./index-CwtlLwRh.js";import{f as G,w,ak as j,G as S,aN as r,J as U,a,O as u,A}from"./@vue/runtime-core-tF_2qJHK.js";import{y as n,u as y,r as J}from"./@vue/reactivity-BmZ-20sQ.js";import{Q as k}from"./@vue/shared-mAAVTE9n.js";const M={class:"pr-8"},L=G({__name:"account-adjust",props:{show:{type:Boolean,required:!0},value:{type:[Number,String],required:!0}},emits:["update:show","confirm"],setup(d,{emit:V}){const s=y(),i=d,f=V,o=J({action:1,num:"",remark:""}),m=y(),c=A(()=>Number(i.value)+Number(o.num)*(o.action==1?1:-1)),R={num:[{required:!0,message:"请输入调整的金额"}]},g=e=>{if(e.includes("-"))return b.msgError("请输入正整数");o.num=e},x=async()=>{var e;await((e=s.value)==null?void 0:e.validate()),f("confirm",o)},C=()=>{var e;f("update:show",!1),(e=s.value)==null||e.resetFields()};return w(()=>i.show,e=>{var t,l;e?(t=m.value)==null||t.open():(l=m.value)==null||l.close()}),w(c,e=>{e<0&&(b.msgError("调整后余额需大于0"),o.num="")}),(e,t)=>{const l=B,_=I,E=q,v=D,N=h;return j(),S(F,{ref_key:"popupRef",ref:m,title:"余额调整",width:"500px",onConfirm:x,async:!0,onClose:C},{default:r(()=>[U("div",M,[a(N,{ref_key:"formRef",ref:s,model:n(o),"label-width":"120px",rules:R},{default:r(()=>[a(l,{label:"当前余额"},{default:r(()=>[u("¥ "+k(d.value),1)]),_:1}),a(l,{label:"余额增减",required:"",prop:"action"},{default:r(()=>[a(E,{modelValue:n(o).action,"onUpdate:modelValue":t[0]||(t[0]=p=>n(o).action=p)},{default:r(()=>[a(_,{value:1},{default:r(()=>[...t[2]||(t[2]=[u("增加余额",-1)])]),_:1}),a(_,{value:2},{default:r(()=>[...t[3]||(t[3]=[u("扣减余额",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),a(l,{label:"调整余额",prop:"num"},{default:r(()=>[a(v,{"model-value":n(o).num,placeholder:"请输入调整的金额",type:"number",onInput:g},null,8,["model-value"])]),_:1}),a(l,{label:"调整后余额"},{default:r(()=>[u(" ¥ "+k(n(c)),1)]),_:1}),a(l,{label:"备注",prop:"remark"},{default:r(()=>[a(v,{modelValue:n(o).remark,"onUpdate:modelValue":t[1]||(t[1]=p=>n(o).remark=p),type:"textarea",rows:4},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])])]),_:1},512)}}});export{L as _};
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{_ as o}from"./add-nav.vue_vue_type_script_setup_true_lang-sBiTV4qR.js";import"./element-plus-NSC30APV.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@vue/runtime-core-tF_2qJHK.js";import"./@vue/reactivity-BmZ-20sQ.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-LZuIxEs_.js";import"./index-CwtlLwRh.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";import"./picker-DTygJq-z.js";import"./index-CgAEaJvF.js";import"./index.vue_vue_type_script_setup_true_lang-D53L8u8U.js";import"./article-BYsri_-7.js";import"./usePaging-BIG1oWvJ.js";import"./picker-Z4o1kfTj.js";import"./index-DOquUsOX.js";import"./index-CFOWc_EU.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-ByJn2Em4.js";import"./index.vue_vue_type_script_setup_true_lang-DXsNLQSJ.js";import"./vuedraggable-Bl4C18MR.js";import"./vue-BEnQNo4t.js";import"./@vue/compiler-dom-CqayqxS7.js";import"./@vue/compiler-core-CvbQOXIO.js";import"./sortablejs-dsEAUXlE.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./add-nav.vue_vue_type_script_setup_true_lang-CLFObqD9.js";import"./element-plus-FSf94q2-.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/runtime-core-C6bnekPw.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-Dn5DJbNI.js";import"./index-CLwyu9dm.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";import"./picker-BdCBwiHB.js";import"./index-CbVXHb-T.js";import"./index.vue_vue_type_script_setup_true_lang-CcHKbLKc.js";import"./article-W2gheZBz.js";import"./usePaging-VsbTxSU0.js";import"./picker-S140y0Ck.js";import"./index-Ddx1af9I.js";import"./index-iCSIrF-J.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-C8XkNg4E.js";import"./index.vue_vue_type_script_setup_true_lang-zIjDr0d2.js";import"./vuedraggable-5bKFmC7X.js";import"./vue-BVs68q8v.js";import"./@vue/compiler-dom-CqayqxS7.js";import"./@vue/compiler-core-CvbQOXIO.js";import"./sortablejs-dsEAUXlE.js";export{o as default};
@@ -1 +1 @@
import{C as E,B,g as C,i as N}from"./element-plus-NSC30APV.js";import{_ as $}from"./index-LZuIxEs_.js";import{_ as z}from"./picker-DTygJq-z.js";import{_ as A}from"./picker-Z4o1kfTj.js";import{c as D,i as r}from"./index-CwtlLwRh.js";import{D as I}from"./vuedraggable-Bl4C18MR.js";import{f as R,ak as p,I as F,J as l,a,aN as d,G,O as J,A as L}from"./@vue/runtime-core-tF_2qJHK.js";import{y as c,a as O}from"./@vue/reactivity-BmZ-20sQ.js";const P={class:"bg-fill-light flex items-center w-full p-4 mb-4"},S={class:"upload-btn w-[60px] h-[60px]"},T={class:"ml-3 flex-1"},j={class:"flex items-center"},q={class:"flex items-center mt-[18px]"},H={class:"flex-1 flex items-center"},K={class:"drag-move cursor-move ml-auto"},oe=R({__name:"add-nav",props:{modelValue:{type:Array,default:()=>[]},max:{type:Number,default:100},min:{type:Number,default:1}},emits:["update:modelValue"],setup(_,{emit:f}){const t=_,V=f,m=L({get(){return t.modelValue},set(s){V("update:modelValue",s)}}),x=()=>{var s;((s=t.modelValue)==null?void 0:s.length)<t.max?m.value.push({image:"",name:"导航名称",link:{},is_show:"1"}):r.msgError(`最多添加${t.max}`)},g=s=>{var e;if(((e=t.modelValue)==null?void 0:e.length)<=t.min)return r.msgError(`最少保留${t.min}`);m.value.splice(s,1)};return(s,e)=>{const i=D,v=A,h=E,k=z,b=C,w=B,y=$,U=N;return p(),F("div",null,[l("div",null,[a(c(I),{class:"draggable",modelValue:c(m),"onUpdate:modelValue":e[0]||(e[0]=o=>O(m)?m.value=o:null),animation:"300",handle:".drag-move","item-key":"index"},{item:d(({element:o,index:u})=>[(p(),G(y,{class:"w-[467px]",key:u,onClose:n=>g(u)},{default:d(()=>[l("div",P,[a(v,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body",size:"60px","exclude-domain":""},{upload:d(()=>[l("div",S,[a(i,{name:"el-icon-Plus",size:20})])]),_:1},8,["modelValue","onUpdate:modelValue"]),l("div",T,[l("div",j,[e[1]||(e[1]=l("span",{class:"text-tx-regular flex-none mr-3"},"名称",-1)),a(h,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),l("div",q,[e[2]||(e[2]=l("span",{class:"text-tx-regular flex-none mr-3"},"链接",-1)),a(k,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),a(w,{label:"是否显示",class:"mt-[18px]"},{default:d(()=>[l("div",H,[a(b,{modelValue:o.is_show,"onUpdate:modelValue":n=>o.is_show=n,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),l("div",K,[a(i,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])])]),_:2},1032,["onClose"]))]),_:1},8,["modelValue"])]),l("div",null,[a(U,{type:"primary",onClick:x},{default:d(()=>[...e[3]||(e[3]=[J("添加",-1)])]),_:1})])])}}});export{oe as _};
import{C as E,B,g as C,i as N}from"./element-plus-FSf94q2-.js";import{_ as $}from"./index-Dn5DJbNI.js";import{_ as z}from"./picker-BdCBwiHB.js";import{_ as A}from"./picker-S140y0Ck.js";import{c as D,i as r}from"./index-CLwyu9dm.js";import{D as I}from"./vuedraggable-5bKFmC7X.js";import{f as R,ak as p,I as F,J as l,a,aN as d,G,O as J,A as L}from"./@vue/runtime-core-C6bnekPw.js";import{y as c,a as O}from"./@vue/reactivity-DiY1c2vO.js";const P={class:"bg-fill-light flex items-center w-full p-4 mb-4"},S={class:"upload-btn w-[60px] h-[60px]"},T={class:"ml-3 flex-1"},j={class:"flex items-center"},q={class:"flex items-center mt-[18px]"},H={class:"flex-1 flex items-center"},K={class:"drag-move cursor-move ml-auto"},oe=R({__name:"add-nav",props:{modelValue:{type:Array,default:()=>[]},max:{type:Number,default:100},min:{type:Number,default:1}},emits:["update:modelValue"],setup(_,{emit:f}){const t=_,V=f,m=L({get(){return t.modelValue},set(s){V("update:modelValue",s)}}),x=()=>{var s;((s=t.modelValue)==null?void 0:s.length)<t.max?m.value.push({image:"",name:"导航名称",link:{},is_show:"1"}):r.msgError(`最多添加${t.max}`)},g=s=>{var e;if(((e=t.modelValue)==null?void 0:e.length)<=t.min)return r.msgError(`最少保留${t.min}`);m.value.splice(s,1)};return(s,e)=>{const i=D,v=A,h=E,k=z,b=C,w=B,y=$,U=N;return p(),F("div",null,[l("div",null,[a(c(I),{class:"draggable",modelValue:c(m),"onUpdate:modelValue":e[0]||(e[0]=o=>O(m)?m.value=o:null),animation:"300",handle:".drag-move","item-key":"index"},{item:d(({element:o,index:u})=>[(p(),G(y,{class:"w-[467px]",key:u,onClose:n=>g(u)},{default:d(()=>[l("div",P,[a(v,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body",size:"60px","exclude-domain":""},{upload:d(()=>[l("div",S,[a(i,{name:"el-icon-Plus",size:20})])]),_:1},8,["modelValue","onUpdate:modelValue"]),l("div",T,[l("div",j,[e[1]||(e[1]=l("span",{class:"text-tx-regular flex-none mr-3"},"名称",-1)),a(h,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),l("div",q,[e[2]||(e[2]=l("span",{class:"text-tx-regular flex-none mr-3"},"链接",-1)),a(k,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),a(w,{label:"是否显示",class:"mt-[18px]"},{default:d(()=>[l("div",H,[a(b,{modelValue:o.is_show,"onUpdate:modelValue":n=>o.is_show=n,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),l("div",K,[a(i,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])])]),_:2},1032,["onClose"]))]),_:1},8,["modelValue"])]),l("div",null,[a(U,{type:"primary",onClick:x},{default:d(()=>[...e[3]||(e[3]=[J("添加",-1)])]),_:1})])])}}});export{oe as _};
@@ -1 +1 @@
import{r as n}from"./index-CwtlLwRh.js";function e(t){return n.get({url:"/auth.admin/lists",params:t},{ignoreCancelToken:!0})}function i(t){return n.post({url:"/auth.admin/add",params:t})}function r(t){return n.post({url:"/auth.admin/edit",params:t})}function u(t){return n.post({url:"/auth.admin/delete",params:t})}function d(t){return n.get({url:"/auth.admin/detail",params:t})}export{e as a,r as b,u as c,i as d,d as e};
import{r as n}from"./index-CLwyu9dm.js";function e(t){return n.get({url:"/auth.admin/lists",params:t},{ignoreCancelToken:!0})}function i(t){return n.post({url:"/auth.admin/add",params:t})}function r(t){return n.post({url:"/auth.admin/edit",params:t})}function u(t){return n.post({url:"/auth.admin/delete",params:t})}function d(t){return n.get({url:"/auth.admin/detail",params:t})}export{e as a,r as b,u as c,i as d,d as e};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
.today-block-alert[data-v-0586cc07]{margin-bottom:16px}.appointment-form[data-v-0586cc07] .el-form-item__label{font-weight:500}.appointment-form .channel-source-select[data-v-0586cc07]{width:100%;max-width:360px}.doctor-list[data-v-0586cc07]{display:flex;flex-wrap:wrap;gap:12px}.doctor-list .doctor-radio[data-v-0586cc07]{margin-right:0}.doctor-list .doctor-radio[data-v-0586cc07] .el-radio__label{display:flex;align-items:center}.appointment-time-container[data-v-0586cc07]{width:100%}.date-selector[data-v-0586cc07]{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:20px}.date-selector .date-button[data-v-0586cc07]{min-width:130px;height:40px;font-size:14px;border-radius:8px;transition:all .2s}.date-selector .date-button[data-v-0586cc07]:hover{transform:translateY(-2px);box-shadow:0 2px 8px #0000001a}.time-slots-container[data-v-0586cc07]{background-color:#f8f9fa;border-radius:8px;padding:16px}.time-slots-header[data-v-0586cc07]{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.time-slots-header .header-title[data-v-0586cc07]{font-size:15px;font-weight:600;color:#303133}.time-slots-grid[data-v-0586cc07]{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:10px;max-height:450px;overflow-y:auto;padding:2px}.time-slots-grid[data-v-0586cc07]::-webkit-scrollbar{width:6px}.time-slots-grid[data-v-0586cc07]::-webkit-scrollbar-thumb{background-color:#dcdfe6;border-radius:3px}.time-slots-grid[data-v-0586cc07]::-webkit-scrollbar-thumb:hover{background-color:#c0c4cc}.time-slots-grid .time-slot-item[data-v-0586cc07]{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:0 8px;border:2px solid #e4e7ed;border-radius:8px;cursor:pointer;transition:all .2s;background-color:#fff;min-height:70px}.time-slots-grid .time-slot-item .slot-time[data-v-0586cc07]{font-size:15px;font-weight:600;color:#303133;margin-bottom:6px}.time-slots-grid .time-slot-item .slot-status[data-v-0586cc07]{font-size:12px;color:#909399;padding:0 8px;border-radius:4px;background-color:#f4f4f5}.time-slots-grid .time-slot-item .slot-status.status-available[data-v-0586cc07]{color:#67c23a;background-color:#f0f9ff}.time-slots-grid .time-slot-item.available[data-v-0586cc07]{border-color:#e4e7ed}.time-slots-grid .time-slot-item.available[data-v-0586cc07]:hover{border-color:#409eff;background-color:#ecf5ff;transform:translateY(-2px);box-shadow:0 4px 12px #409eff26}.time-slots-grid .time-slot-item.unavailable[data-v-0586cc07]{background-color:#f5f7fa;border-color:#e4e7ed;cursor:not-allowed;opacity:.6}.time-slots-grid .time-slot-item.unavailable .slot-time[data-v-0586cc07]{color:#c0c4cc}.time-slots-grid .time-slot-item.unavailable .slot-status[data-v-0586cc07]{color:#c0c4cc;background-color:#f5f7fa}.time-slots-grid .time-slot-item.unavailable[data-v-0586cc07]:hover{transform:none;box-shadow:none}.time-slots-grid .time-slot-item.selected[data-v-0586cc07]{border-color:#409eff;background:linear-gradient(135deg,#409eff,#66b1ff);box-shadow:0 4px 12px #409eff4d}.time-slots-grid .time-slot-item.selected .slot-time[data-v-0586cc07]{color:#fff}.time-slots-grid .time-slot-item.selected .slot-status[data-v-0586cc07]{color:#fff;background-color:#fff3}[data-v-0586cc07] .el-radio-group{display:flex;flex-wrap:wrap;gap:12px}[data-v-0586cc07] .el-radio{margin-right:0}.drawer-footer[data-v-0586cc07]{display:flex;justify-content:flex-end;gap:12px;padding:12px 0}
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
.today-block-alert[data-v-0ae1f57a]{margin-bottom:16px}.appointment-form[data-v-0ae1f57a] .el-form-item__label{font-weight:500}.appointment-form .channel-source-select[data-v-0ae1f57a]{width:100%;max-width:360px}.doctor-list[data-v-0ae1f57a]{display:flex;flex-wrap:wrap;gap:12px}.doctor-list .doctor-radio[data-v-0ae1f57a]{margin-right:0}.doctor-list .doctor-radio[data-v-0ae1f57a] .el-radio__label{display:flex;align-items:center}.appointment-time-container[data-v-0ae1f57a]{width:100%}.date-selector[data-v-0ae1f57a]{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:20px}.date-selector .date-button[data-v-0ae1f57a]{min-width:130px;height:40px;font-size:14px;border-radius:8px;transition:all .2s}.date-selector .date-button[data-v-0ae1f57a]:hover{transform:translateY(-2px);box-shadow:0 2px 8px #0000001a}.time-slots-container[data-v-0ae1f57a]{background-color:#f8f9fa;border-radius:8px;padding:16px}.time-slots-header[data-v-0ae1f57a]{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px}.time-slots-header .header-title[data-v-0ae1f57a]{font-size:15px;font-weight:600;color:#303133}.time-slots-grid[data-v-0ae1f57a]{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:10px;max-height:450px;overflow-y:auto;padding:2px}.time-slots-grid[data-v-0ae1f57a]::-webkit-scrollbar{width:6px}.time-slots-grid[data-v-0ae1f57a]::-webkit-scrollbar-thumb{background-color:#dcdfe6;border-radius:3px}.time-slots-grid[data-v-0ae1f57a]::-webkit-scrollbar-thumb:hover{background-color:#c0c4cc}.time-slots-grid .time-slot-item[data-v-0ae1f57a]{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:0 8px;border:2px solid #e4e7ed;border-radius:8px;cursor:pointer;transition:all .2s;background-color:#fff;min-height:70px}.time-slots-grid .time-slot-item .slot-time[data-v-0ae1f57a]{font-size:15px;font-weight:600;color:#303133;margin-bottom:6px}.time-slots-grid .time-slot-item .slot-status[data-v-0ae1f57a]{font-size:12px;color:#909399;padding:0 8px;border-radius:4px;background-color:#f4f4f5}.time-slots-grid .time-slot-item .slot-status.status-available[data-v-0ae1f57a]{color:#67c23a;background-color:#f0f9ff}.time-slots-grid .time-slot-item.available[data-v-0ae1f57a]{border-color:#e4e7ed}.time-slots-grid .time-slot-item.available[data-v-0ae1f57a]:hover{border-color:#409eff;background-color:#ecf5ff;transform:translateY(-2px);box-shadow:0 4px 12px #409eff26}.time-slots-grid .time-slot-item.unavailable[data-v-0ae1f57a]{background-color:#f5f7fa;border-color:#e4e7ed;cursor:not-allowed;opacity:.6}.time-slots-grid .time-slot-item.unavailable .slot-time[data-v-0ae1f57a]{color:#c0c4cc}.time-slots-grid .time-slot-item.unavailable .slot-status[data-v-0ae1f57a]{color:#c0c4cc;background-color:#f5f7fa}.time-slots-grid .time-slot-item.unavailable[data-v-0ae1f57a]:hover{transform:none;box-shadow:none}.time-slots-grid .time-slot-item.selected[data-v-0ae1f57a]{border-color:#409eff;background:linear-gradient(135deg,#409eff,#66b1ff);box-shadow:0 4px 12px #409eff4d}.time-slots-grid .time-slot-item.selected .slot-time[data-v-0ae1f57a]{color:#fff}.time-slots-grid .time-slot-item.selected .slot-status[data-v-0ae1f57a]{color:#fff;background-color:#fff3}[data-v-0ae1f57a] .el-radio-group{display:flex;flex-wrap:wrap;gap:12px}[data-v-0ae1f57a] .el-radio{margin-right:0}.drawer-footer[data-v-0ae1f57a]{display:flex;justify-content:flex-end;gap:12px;padding:12px 0}
@@ -1 +1 @@
import{r as e}from"./index-CwtlLwRh.js";function a(t){return e.get({url:"/article.articleCate/lists",params:t})}function l(t){return e.get({url:"/article.articleCate/all",params:t})}function i(t){return e.post({url:"/article.articleCate/add",params:t})}function c(t){return e.post({url:"/article.articleCate/edit",params:t})}function u(t){return e.post({url:"/article.articleCate/delete",params:t})}function n(t){return e.get({url:"/article.articleCate/detail",params:t})}function s(t){return e.post({url:"/article.articleCate/updateStatus",params:t})}function o(t){return e.get({url:"/article.article/lists",params:t})}function d(t){return e.post({url:"/article.article/add",params:t})}function f(t){return e.post({url:"/article.article/edit",params:t})}function C(t){return e.post({url:"/article.article/delete",params:t})}function p(t){return e.get({url:"/article.article/detail",params:t})}function g(t){return e.post({url:"/article.article/updateStatus",params:t})}export{a,u as b,s as c,c as d,i as e,n as f,p as g,f as h,d as i,l as j,o as k,g as l,C as m};
import{r as e}from"./index-CLwyu9dm.js";function a(t){return e.get({url:"/article.articleCate/lists",params:t})}function l(t){return e.get({url:"/article.articleCate/all",params:t})}function i(t){return e.post({url:"/article.articleCate/add",params:t})}function c(t){return e.post({url:"/article.articleCate/edit",params:t})}function u(t){return e.post({url:"/article.articleCate/delete",params:t})}function n(t){return e.get({url:"/article.articleCate/detail",params:t})}function s(t){return e.post({url:"/article.articleCate/updateStatus",params:t})}function o(t){return e.get({url:"/article.article/lists",params:t})}function d(t){return e.post({url:"/article.article/add",params:t})}function f(t){return e.post({url:"/article.article/edit",params:t})}function C(t){return e.post({url:"/article.article/delete",params:t})}function p(t){return e.get({url:"/article.article/detail",params:t})}function g(t){return e.post({url:"/article.article/updateStatus",params:t})}export{a,u as b,s as c,c as d,i as e,n as f,p as g,f as h,d as i,l as j,o as k,g as l,C as m};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-LpW82yJ0.js";import"./element-plus-FSf94q2-.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/runtime-core-C6bnekPw.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./add-nav.vue_vue_type_script_setup_true_lang-CLFObqD9.js";import"./index-Dn5DJbNI.js";import"./index-CLwyu9dm.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";import"./picker-BdCBwiHB.js";import"./index-CbVXHb-T.js";import"./index.vue_vue_type_script_setup_true_lang-CcHKbLKc.js";import"./article-W2gheZBz.js";import"./usePaging-VsbTxSU0.js";import"./picker-S140y0Ck.js";import"./index-Ddx1af9I.js";import"./index-iCSIrF-J.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-C8XkNg4E.js";import"./index.vue_vue_type_script_setup_true_lang-zIjDr0d2.js";import"./vuedraggable-5bKFmC7X.js";import"./vue-BVs68q8v.js";import"./@vue/compiler-dom-CqayqxS7.js";import"./@vue/compiler-core-CvbQOXIO.js";import"./sortablejs-dsEAUXlE.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CKrj1IU6.js";import"./element-plus-FSf94q2-.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/runtime-core-C6bnekPw.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-BDOO1F0I.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-Dn5DJbNI.js";import"./index-CLwyu9dm.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-QlpZ4wdW.js";import"./pinia-B8cvXbiZ.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-C4onkBvW.js";import"./picker-BdCBwiHB.js";import"./index-CbVXHb-T.js";import"./index.vue_vue_type_script_setup_true_lang-CcHKbLKc.js";import"./article-W2gheZBz.js";import"./usePaging-VsbTxSU0.js";import"./picker-S140y0Ck.js";import"./index-Ddx1af9I.js";import"./index-iCSIrF-J.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-C8XkNg4E.js";import"./index.vue_vue_type_script_setup_true_lang-zIjDr0d2.js";import"./vuedraggable-5bKFmC7X.js";import"./vue-BVs68q8v.js";import"./@vue/compiler-dom-CqayqxS7.js";import"./@vue/compiler-core-CvbQOXIO.js";import"./sortablejs-dsEAUXlE.js";export{o as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-ChKJn1wI.js";import"./@vue/runtime-core-C6bnekPw.js";import"./@vue/reactivity-DiY1c2vO.js";import"./@vue/shared-mAAVTE9n.js";import"./lodash-D3kF6u-c.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-C0Tf93TA.js";import"./@vue/runtime-core-tF_2qJHK.js";import"./@vue/reactivity-BmZ-20sQ.js";import"./@vue/shared-mAAVTE9n.js";import"./lodash-D3kF6u-c.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CHIW8Pak.js";import"./element-plus-NSC30APV.js";import"./@vue/runtime-dom-CEiKlVMn.js";import"./lodash-D3kF6u-c.js";import"./@vue/runtime-core-tF_2qJHK.js";import"./@vue/reactivity-BmZ-20sQ.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-CCtJZkK4.js";import"./lodash-es-C2A-Pj28.js";import"./@popperjs/core-C5az9QE8.js";import"./dayjs-DG77mNTn.js";import"./@ctrl/tinycolor-BuyEbX8F.js";import"./async-validator-CFA_igpM.js";import"./normalize-wheel-es-BQoi3Ox2.js";import"./index-LZuIxEs_.js";import"./index-CwtlLwRh.js";import"./jspdf-BsthCvR5.js";import"./@babel/runtime-BanGtE2-.js";import"./fflate-_ayOYiT1.js";import"./vue-router-BjeWxBI0.js";import"./pinia-CTWOnonq.js";import"./axios-C80V62Fs.js";import"./@vueuse/core-QlbCbZWN.js";import"./@vueuse/shared-Bl-RnC0s.js";import"./css-color-function-DI01JAaZ.js";import"./balanced-match-BdS7OldZ.js";import"./color-B2zxaWkI.js";import"./clone-DBZ6_OiU.js";import"./color-convert-OrFsTA_V.js";import"./color-name-Dju3oUBS.js";import"./color-string-pUQDDJII.js";import"./ms-CzQ2E3wO.js";import"./vue-clipboard3-DByT_rEQ.js";import"./clipboard-CHgxszqY.js";import"./echarts-CNLwa9wG.js";import"./tslib-BDyQ-Jie.js";import"./zrender-DRNXw7y3.js";import"./highlight.js-Bxt7hFFy.js";import"./@highlightjs/vue-plugin-Bm7NQW9r.js";import"./picker-DTygJq-z.js";import"./index-CgAEaJvF.js";import"./index.vue_vue_type_script_setup_true_lang-D53L8u8U.js";import"./article-BYsri_-7.js";import"./usePaging-BIG1oWvJ.js";import"./picker-Z4o1kfTj.js";import"./index-DOquUsOX.js";import"./index-CFOWc_EU.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-ByJn2Em4.js";import"./index.vue_vue_type_script_setup_true_lang-DXsNLQSJ.js";import"./vuedraggable-Bl4C18MR.js";import"./vue-BEnQNo4t.js";import"./@vue/compiler-dom-CqayqxS7.js";import"./@vue/compiler-core-CvbQOXIO.js";import"./sortablejs-dsEAUXlE.js";export{o as default};

Some files were not shown because too many files have changed in this diff Show More