Compare commits

...
Author SHA1 Message Date
longandCursor 679e61057b fix(stats/self_input): 唯一索引含 delete_time,软删后可重新录入
去掉「同日+同渠道」全局唯一,回到按录入人判重;唯一索引补 delete_time 避免软删占键导致 1062;错误提示带冲突记录 ID,迁移脚本兼容多次执行。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 17:01:58 +08:00
long 003810114b debug 2026-05-22 16:45:28 +08:00
longandCursor e4f181e4fe fix(stats/self_input): 渠道字典、财务脱敏与同日同渠道全局唯一
自媒体来源改推广渠道字典;非白名单隐藏账户消耗/ROI;部门展示完整路径;业绩与消耗按日期+渠道全局去重。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 12:02:12 +08:00
longandCursor bba989c0af fix(stats/self_input): 修复保存不入库/路由 404,补全部门与自媒体来源下拉
- 模型去掉 defaultSoftDelete=0,避免 ThinkPHP 软删过滤导致新增记录"隐形"
- 菜单 paths 改相对路径并新增「自录数据统计」目录,迁移已有菜单
- Lists/Overview 补部门关联、支持按部门筛选
- 数据权限改由 self_input_stats_view_all_roles 白名单 + DataScope 控制,
  编辑/删除完全交给按钮权限校验(移除"仅本人可改"硬限制)
- 新增 /stats.self_input/mediaSourceOptions 接口,统计页/账户消耗页/录入弹窗
  共用 useMediaSourceOptions + MediaSourceSelect,去重动态加载

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 11:47:15 +08:00
longandCursor 183b6a1acf feat(stats): 新增自录转化统计模块
支持后台用户手动录入个人业绩与账户消耗,独立计算转化指标,接入 DataScope 数据权限。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 09:17:16 +08:00
Your Name 49c8c95966 更新 2026-05-21 14:41:43 +08:00
Your Name c7c264497e 修复bug 2026-05-21 14:38:31 +08:00
Your Name ba1c067dce Merge branch 'master' into bug-5-20 2026-05-20 17:15:51 +08:00
Your Name 5e96fda88f 更新 2026-05-20 17:14:27 +08:00
Your Name 93e6d02ce4 更新 2026-05-20 16:53:19 +08:00
Your Name 3e4039efb0 更新 2026-05-20 15:40:01 +08:00
321 changed files with 5808 additions and 817 deletions
+50
View File
@@ -0,0 +1,50 @@
import request from '@/utils/request'
export function getSelfInputOverview(params: any) {
return request.get({ url: '/stats.self_input/overview', params })
}
/** 自媒体来源下拉(业绩+账户消耗已录入值去重) */
export function getSelfInputMediaSourceOptions() {
return request.get({ url: '/stats.self_input/mediaSourceOptions' })
}
export function personalYejiLists(params: any) {
return request.get({ url: '/stats.personal_yeji/lists', params })
}
export function personalYejiAdd(data: any) {
return request.post({ url: '/stats.personal_yeji/add', data })
}
export function personalYejiEdit(data: any) {
return request.post({ url: '/stats.personal_yeji/edit', data })
}
export function personalYejiDetail(params: any) {
return request.get({ url: '/stats.personal_yeji/detail', params })
}
export function personalYejiDelete(params: any) {
return request.post({ url: '/stats.personal_yeji/delete', params })
}
export function personalAccountCostLists(params: any) {
return request.get({ url: '/stats.personal_account_cost/lists', params })
}
export function personalAccountCostAdd(data: any) {
return request.post({ url: '/stats.personal_account_cost/add', data })
}
export function personalAccountCostEdit(data: any) {
return request.post({ url: '/stats.personal_account_cost/edit', data })
}
export function personalAccountCostDetail(params: any) {
return request.get({ url: '/stats.personal_account_cost/detail', params })
}
export function personalAccountCostDelete(params: any) {
return request.post({ url: '/stats.personal_account_cost/delete', params })
}
File diff suppressed because it is too large Load Diff
+472 -97
View File
@@ -407,20 +407,35 @@
</div>
<div class="rx-herbs">
<div
v-for="(h, i) in slipHerbsList"
:key="i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
<template v-if="slipMainHerbs.length">
<div class="rx-herb-section-label">主方</div>
<div
v-for="(h, i) in slipMainHerbs"
:key="'main-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
</template>
<template v-if="slipAuxHerbs.length">
<div class="rx-herb-section-label rx-herb-section-label--aux">辅方</div>
<div
v-for="(h, i) in slipAuxHerbs"
:key="'aux-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
</template>
</div>
</div>
<!-- 服法 / 医嘱 / 备注 / 药房备注 / 出丸 -->
<div class="rx-text">
<p>服法{{ rxUsageText }}</p>
<p>主方服法{{ rxUsageText }}</p>
<p v-if="rxAuxUsageText">辅方服法{{ rxAuxUsageText }}</p>
<p v-if="rxAdviceText">医嘱{{ rxAdviceText }}</p>
<p v-if="rxRemarkText">备注{{ rxRemarkText }}</p>
<p v-if="rxPharmacyRemarkText" class="rx-text-warn">
@@ -649,53 +664,87 @@
<el-form-item label="药材配方" prop="herbs" required>
<div class="w-full">
<div class="flex flex-wrap items-center gap-2">
<el-button type="primary" size="small" @click="addHerb">
添加药材
</el-button>
<el-button type="success" size="small" @click="openLibraryDialog">
<el-button
type="success"
size="small"
v-perms="['cf.prescription/add', 'cf.prescription/edit', 'tcm.prescriptionLibrary/lists']"
@click="openLibraryDialog"
>
从处方库导入
</el-button>
</div>
<div class="mt-2">
<el-button type="warning" size="small" plain :icon="EditPen" @click="openPasteRecipeDialog">
导入药方
</el-button>
<span class="text-xs text-gray-500 ml-2 align-middle">
粘贴文本解析药名与剂量;须与药品库名称完全一致才录入
<span class="text-xs text-gray-500">
粘贴文本解析药名与剂量;须与药品库名称完全一致才录入(导入至主方)
</span>
</div>
<el-table :data="editForm.herbs" class="mt-2" border>
<el-table-column label="序号" type="index" width="60" />
<el-table-column label="药材名称" min-width="220">
<template #default="{ row }">
<MedicineNameSelect v-model="row.name" class="w-full" />
</template>
</el-table-column>
<el-table-column label="剂量(克)" min-width="120">
<template #default="{ row, $index }">
<el-input-number
v-model="row.dosage"
:min="0"
:precision="1"
:step="0.5"
placeholder="剂量"
class="w-full"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="{ $index }">
<el-button
type="danger"
link
@click="removeHerb($index)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="herb-formula-block mt-3">
<div class="herb-formula-block__head">
<el-tag type="primary" size="small">主方</el-tag>
<el-button type="primary" size="small" @click="addHerb('主方')">添加主方药材</el-button>
</div>
<el-table :data="mainHerbRows" class="mt-2" border empty-text="暂无主方药材">
<el-table-column label="序号" type="index" width="60" />
<el-table-column label="药材名称" min-width="220">
<template #default="{ row }">
<MedicineNameSelect v-model="editForm.herbs[row.index].name" class="w-full" />
</template>
</el-table-column>
<el-table-column label="剂量(克)" min-width="120">
<template #default="{ row }">
<el-input-number
v-model="editForm.herbs[row.index].dosage"
:min="0"
:precision="1"
:step="0.5"
placeholder="剂量"
class="w-full"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="{ row }">
<el-button type="danger" link @click="removeHerb(row.index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="herb-formula-block mt-4">
<div class="herb-formula-block__head">
<el-tag type="warning" size="small">辅方</el-tag>
<el-button type="primary" size="small" plain @click="addHerb('辅方')">
添加辅方药材
</el-button>
</div>
<el-table :data="auxHerbRows" class="mt-2" border empty-text="暂无辅方药材">
<el-table-column label="序号" type="index" width="60" />
<el-table-column label="药材名称" min-width="220">
<template #default="{ row }">
<MedicineNameSelect v-model="editForm.herbs[row.index].name" class="w-full" />
</template>
</el-table-column>
<el-table-column label="剂量(克)" min-width="120">
<template #default="{ row }">
<el-input-number
v-model="editForm.herbs[row.index].dosage"
:min="0"
:precision="1"
:step="0.5"
placeholder="剂量"
class="w-full"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<template #default="{ row }">
<el-button type="danger" link @click="removeHerb(row.index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<el-alert
v-if="editMode === 'edit'"
type="warning"
@@ -778,8 +827,10 @@
<el-option label="汤剂" value="汤剂" />
</el-select>
</el-form-item> </el-col>
<!-- 用量字段 -->
</el-row>
<div class="usage-formula-title usage-formula-title--main">主方用法</div>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="用量" prop="dosage_amount">
<!-- 浓缩水丸:1-10g 下拉选择 -->
@@ -881,6 +932,97 @@
</el-form-item>
</el-col>
</el-row>
<template v-if="auxHerbRows.length > 0">
<div class="usage-formula-title usage-formula-title--aux">辅方用法</div>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="用量">
<el-select
v-if="editForm.prescription_type === '浓缩水丸'"
v-model="editForm.aux_usage.dosage_amount"
placeholder="请选择用量"
class="w-full"
>
<el-option v-for="n in 10" :key="n" :label="n + 'g'" :value="n" />
</el-select>
<el-select
v-else-if="editForm.prescription_type === '饮片'"
v-model="editForm.aux_usage.dosage_amount"
placeholder="请选择用量"
class="w-full"
>
<el-option label="50ml" :value="50" />
<el-option label="100ml" :value="100" />
<el-option label="120ml" :value="120" />
<el-option label="150ml" :value="150" />
<el-option label="180ml" :value="180" />
<el-option label="200ml" :value="200" />
<el-option label="250ml" :value="250" />
</el-select>
<el-input-number
v-else
v-model="editForm.aux_usage.dosage_amount"
:min="0"
:precision="2"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col v-if="editForm.prescription_type === '浓缩水丸'" :span="8">
<el-form-item label=" " label-width="12px">
<el-select
v-model="editForm.aux_usage.dosage_bag_count"
placeholder="请选择袋数"
class="w-[120px]"
>
<el-option label="1袋" :value="1" />
<el-option label="2袋" :value="2" />
<el-option label="3袋" :value="3" />
<el-option label="4袋" :value="4" />
<el-option label="5袋" :value="5" />
</el-select>
</el-form-item>
</el-col>
<el-col v-if="editForm.prescription_type === '饮片'" :span="8">
<el-form-item label="是否代煎">
<el-radio-group v-model="editForm.aux_usage.need_decoction">
<el-radio :label="true">代煎</el-radio>
<el-radio :label="false">不代煎</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col v-if="editForm.prescription_type === '饮片'" :span="8">
<el-form-item label="每贴出包数">
<el-select v-model="editForm.aux_usage.bags_per_dose" placeholder="请选择" class="w-full">
<el-option v-for="n in 9" :key="n" :label="n + '包'" :value="n" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="每天几次">
<el-input-number
v-model="editForm.aux_usage.times_per_day"
:min="1"
:max="6"
class="!w-full"
placeholder="每天服用次数"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="服用天数">
<el-input-number
v-model="editForm.aux_usage.usage_days"
:min="1"
:max="365"
placeholder="服用天数"
class="w-full"
/>
</el-form-item>
</el-col>
</el-row>
</template>
<el-form-item label="用法" prop="usage_instruction">
<el-input
@@ -1365,16 +1507,17 @@
</template>
</el-dialog>
<!-- 从处方库导入(与诊间 tcm-prescription 一致,按当前处方开方医师 creator_id 筛选) -->
<!-- 从处方库导入:当前开方医师的全部模板 + 所有人可见的公共模板 -->
<el-dialog
v-model="showLibraryDialog"
title="从处方库导入"
width="800px"
:close-on-click-modal="false"
>
<div class="mb-4">
<div class="mb-4 flex gap-3">
<el-input
v-model="librarySearchName"
class="flex-1"
placeholder="请输入处方名称搜索"
clearable
@keyup.enter="searchLibrary"
@@ -1384,6 +1527,24 @@
<el-button :icon="Search" @click="searchLibrary" />
</template>
</el-input>
<el-select
v-model="librarySearchFormulaType"
placeholder="处方类型"
clearable
class="w-[140px]"
@change="searchLibrary"
>
<el-option label="全部" value="" />
<el-option label="主方" value="主方" />
<el-option label="辅方" value="辅方" />
</el-select>
</div>
<div class="mb-3 flex flex-wrap items-center gap-x-4 gap-y-2">
<span class="text-sm text-gray-600 shrink-0">导入方式</span>
<el-radio-group v-model="libraryImportMode">
<el-radio label="replace">覆盖现有药材</el-radio>
<el-radio label="append">追加到末尾</el-radio>
</el-radio-group>
</div>
<el-table
@@ -1394,6 +1555,13 @@
@row-click="handleSelectLibraryRow"
>
<el-table-column label="处方名称" prop="prescription_name" min-width="150" show-overflow-tooltip />
<el-table-column label="处方类型" width="90">
<template #default="{ row }">
<el-tag :type="row.formula_type === '辅方' ? 'warning' : 'primary'" size="small">
{{ row.formula_type || '主方' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="药材数量" width="100">
<template #default="{ row }">
{{ row.herbs?.length || 0 }}味
@@ -1407,6 +1575,13 @@
<span v-else class="text-gray-400">暂无药材</span>
</template>
</el-table-column>
<el-table-column label="是否公开" width="110">
<template #default="{ row }">
<el-tag :type="row.is_public ? 'success' : 'info'" size="small">
{{ row.is_public ? '所有人可见' : '仅自己可见' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="创建人" prop="creator_name" width="100" />
<el-table-column label="操作" width="100" fixed="right">
<template #default="{ row }">
@@ -1522,6 +1697,119 @@ import jsPDF from 'jspdf'
const TcmDiagnosisEditView = defineAsyncComponent(() => import('@/views/tcm/diagnosis/edit.vue'))
type FormulaType = '主方' | '辅方'
type HerbRow = { name: string; dosage: number; formula_type: FormulaType }
type AuxUsageForm = {
dosage_amount?: number
dosage_bag_count: number
need_decoction: boolean
bags_per_dose: number
times_per_day: number
usage_days: number
}
function defaultAuxUsage(prescriptionType = '浓缩水丸'): AuxUsageForm {
if (prescriptionType === '饮片') {
return {
dosage_amount: 50,
dosage_bag_count: 1,
need_decoction: false,
bags_per_dose: 1,
times_per_day: 3,
usage_days: 7
}
}
if (prescriptionType === '浓缩水丸') {
return {
dosage_amount: 5,
dosage_bag_count: 1,
need_decoction: false,
bags_per_dose: 1,
times_per_day: 3,
usage_days: 7
}
}
return {
dosage_amount: 1,
dosage_bag_count: 1,
need_decoction: false,
bags_per_dose: 1,
times_per_day: 3,
usage_days: 7
}
}
function normalizeAuxUsageForm(raw: unknown, prescriptionType: string): AuxUsageForm {
const base = defaultAuxUsage(prescriptionType)
if (!raw || typeof raw !== 'object') return { ...base }
const o = raw as Record<string, unknown>
return {
dosage_amount:
o.dosage_amount !== null && o.dosage_amount !== undefined && o.dosage_amount !== ''
? Number(o.dosage_amount)
: base.dosage_amount,
dosage_bag_count: o.dosage_bag_count != null ? Number(o.dosage_bag_count) || 1 : base.dosage_bag_count,
need_decoction: o.need_decoction === 1 || o.need_decoction === true,
bags_per_dose: o.bags_per_dose != null ? Number(o.bags_per_dose) || 1 : base.bags_per_dose,
times_per_day: o.times_per_day != null ? Number(o.times_per_day) || 3 : base.times_per_day,
usage_days: o.usage_days != null ? Number(o.usage_days) || 7 : base.usage_days
}
}
function buildUsageSegmentText(
usage: {
prescription_type?: string
dosage_amount?: number | null
dosage_unit?: string
dosage_bag_count?: number
times_per_day?: number
usage_way?: string
usage_time?: string
},
fallbackWay?: string,
fallbackTime?: string
): string {
const pt = usage.prescription_type || '浓缩水丸'
const times = Number(usage.times_per_day) > 0 ? Number(usage.times_per_day) : 3
const amount = usage.dosage_amount != null ? Number(usage.dosage_amount) : 10
const unit = usage.dosage_unit || (pt === '饮片' ? 'ml' : 'g')
const usageWay = usage.usage_way || fallbackWay || '温水送服'
const usageTime = usage.usage_time || fallbackTime || ''
const seg: string[] = []
seg.push(`每天${times}次`)
if (pt === '浓缩水丸') {
const bags = Number(usage.dosage_bag_count) > 0 ? Number(usage.dosage_bag_count) : 1
seg.push(`一次${bags}袋`)
seg.push(`每袋${amount}${unit}`)
} else {
seg.push(`一次${amount}${unit}`)
}
seg.push(usageWay)
if (usageTime) seg.push(usageTime)
return seg.join(', ')
}
function normalizeFormulaType(v: unknown): FormulaType {
return v === '辅方' ? '辅方' : '主方'
}
function normalizeHerbRow(raw: any): HerbRow {
return {
name: String(raw?.name ?? '').trim(),
dosage: Number(raw?.dosage) || 0,
formula_type: normalizeFormulaType(raw?.formula_type)
}
}
function normalizeSlipHerbs(raw: unknown): HerbRow[] {
if (!raw) return []
if (Array.isArray(raw)) {
return raw.map((x: any) => normalizeHerbRow(x))
}
return []
}
/** 与 server/config/project.php prescription_audit_roles 保持一致 */
const PRESCRIPTION_AUDIT_ROLE_IDS = [0, 3]
@@ -1923,7 +2211,13 @@ const createOrderHerbSummary = computed(() => {
const row = createOrderPrescription.value
const herbs = normalizeSlipHerbs(row?.herbs)
if (!herbs.length) return '暂无药材明细'
const s = herbs.map((h) => `${h.name} ${h.dosage}g`).join('、')
const main = herbs.filter((h) => normalizeFormulaType(h.formula_type) === '主方')
const aux = herbs.filter((h) => normalizeFormulaType(h.formula_type) === '辅方')
const fmt = (list: HerbRow[]) => list.map((h) => `${h.name} ${h.dosage}g`).join('、')
const parts: string[] = []
if (main.length) parts.push(`主方:${fmt(main)}`)
if (aux.length) parts.push(`辅方:${fmt(aux)}`)
const s = parts.join('')
return s.length > 120 ? `${s.slice(0, 120)}…` : s
})
@@ -2163,9 +2457,27 @@ const editReviveHint = computed(() => {
const slipHerbsList = computed(() => {
const h = slipView.value?.herbs
return Array.isArray(h) ? h : []
return Array.isArray(h) ? (h as HerbRow[]) : []
})
const slipMainHerbs = computed(() =>
slipHerbsList.value.filter((h) => normalizeFormulaType(h.formula_type) === '主方')
)
const slipAuxHerbs = computed(() =>
slipHerbsList.value.filter((h) => normalizeFormulaType(h.formula_type) === '辅方')
)
const mainHerbRows = computed(() =>
editForm.herbs
.map((herb, index) => ({ herb, index }))
.filter(({ herb }) => normalizeFormulaType(herb.formula_type) === '主方')
)
const auxHerbRows = computed(() =>
editForm.herbs
.map((herb, index) => ({ herb, index }))
.filter(({ herb }) => normalizeFormulaType(herb.formula_type) === '辅方')
)
const slipDietaryText = computed(() => {
const d = slipView.value?.dietary_taboo
if (Array.isArray(d)) return d.filter(Boolean).join('、')
@@ -2251,23 +2563,26 @@ const rxUsageText = computed(() => {
const v = slipView.value as any
if (!v) return '—'
if (v.usage_text) return v.usage_text
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
const unit = v.dosage_unit || 'g'
const usageWay = v.usage_way || '温水送服'
const usageTime = v.usage_time || ''
const seg: string[] = []
seg.push(`每天${times}次`)
if ((v.prescription_type || '浓缩水丸') === '浓缩水丸') {
const bags = Number(v.dosage_bag_count) > 0 ? Number(v.dosage_bag_count) : 1
seg.push(`一次${bags}袋`)
seg.push(`每袋${amount}${unit}`)
} else {
seg.push(`一次${amount}${unit}`)
}
seg.push(usageWay)
if (usageTime) seg.push(usageTime)
return seg.join(', ')
return buildUsageSegmentText(v)
})
const rxAuxUsageText = computed(() => {
const v = slipView.value as any
if (!v || !slipAuxHerbs.value.length) return ''
const aux = normalizeAuxUsageForm(v.aux_usage, v.prescription_type || '浓缩水丸')
return buildUsageSegmentText(
{
prescription_type: v.prescription_type,
dosage_amount: aux.dosage_amount,
dosage_unit: v.dosage_unit,
dosage_bag_count: aux.dosage_bag_count,
times_per_day: aux.times_per_day,
usage_way: v.usage_way,
usage_time: v.usage_time
},
v.usage_way,
v.usage_time
)
})
const rxAdviceText = computed(() => {
@@ -2462,7 +2777,7 @@ const editForm = reactive({
pulse: '',
pulse_condition: '',
clinical_diagnosis: '',
herbs: [] as Array<{ name: string; dosage: number }>,
herbs: [] as HerbRow[],
dose_count: 7,
dose_unit: '剂',
usage_days: 7,
@@ -2488,7 +2803,8 @@ const editForm = reactive({
/** 列表带入:业务订单「处方审核」驳回(消费者处方本身可能仍为已通过) */
business_prescription_audit_rejected: 0,
business_prescription_audit_remark: '',
times_per_day: 2
times_per_day: 2,
aux_usage: defaultAuxUsage('浓缩水丸')
})
/** 编辑页:关联业务订单上的服用天数、医助备注(与处方提示一致) */
@@ -2579,6 +2895,7 @@ watch(() => editForm.prescription_type, (newType) => {
editForm.need_decoction = false
editForm.bags_per_dose = 1
}
Object.assign(editForm.aux_usage, defaultAuxUsage(newType))
})
// 表单验证规则
@@ -2807,15 +3124,15 @@ function slipAgeText(age: unknown) {
return `${age}岁`
}
function normalizeSlipHerbs(raw: unknown): Array<{ name: string; dosage: number }> {
if (!raw) return []
if (Array.isArray(raw)) {
return raw.map((x: any) => ({
name: String(x?.name ?? '').trim(),
dosage: Number(x?.dosage) || 0
}))
function herbValidationLabel(globalIndex: number): string {
const herb = editForm.herbs[globalIndex]
if (!herb) return `第${globalIndex + 1}味`
const ft = normalizeFormulaType(herb.formula_type)
let n = 0
for (let i = 0; i <= globalIndex; i++) {
if (normalizeFormulaType(editForm.herbs[i]?.formula_type) === ft) n++
}
return []
return `${ft}第${n}味`
}
function listRxOrderWarnings(row: any): string[] {
@@ -3038,6 +3355,8 @@ const showLibraryDialog = ref(false)
const libraryLoading = ref(false)
const libraryList = ref<any[]>([])
const librarySearchName = ref('')
const librarySearchFormulaType = ref('')
const libraryImportMode = ref<'replace' | 'append'>('replace')
const libraryPage = ref(1)
const libraryPageSize = ref(15)
const libraryTotal = ref(0)
@@ -3082,8 +3401,8 @@ const loadLibraryList = async () => {
page_no: libraryPage.value,
page_size: libraryPageSize.value,
prescription_name: librarySearchName.value,
is_public: '',
creator_id: doctorId
formula_type: librarySearchFormulaType.value,
prescribing_creator_id: doctorId
})
libraryList.value = res?.lists || []
libraryTotal.value = res?.count || 0
@@ -3118,18 +3437,33 @@ const handleImportLibrary = (row: any) => {
feedback.msgWarning('该处方没有药材信息')
return
}
const imported = JSON.parse(JSON.stringify(row.herbs)) as Array<{ name: string; dosage: number }>
editForm.herbs = imported
const formulaType = normalizeFormulaType(row.formula_type)
const imported = (JSON.parse(JSON.stringify(row.herbs)) as any[]).map((h) => ({
...normalizeHerbRow(h),
formula_type: formulaType
}))
if (libraryImportMode.value === 'replace') {
const kept = editForm.herbs.filter((h) => normalizeFormulaType(h.formula_type) !== formulaType)
editForm.herbs = [...kept, ...imported]
} else {
editForm.herbs.push(...imported)
}
const modeHint = libraryImportMode.value === 'append' ? '(已追加)' : ''
if (findDuplicateHerbNamesLocal().length) {
feedback.msgWarning('导入的处方中存在重复药名,请合并剂量或删除多余行')
feedback.msgWarning(
`已导入处方「${row.prescription_name}」${modeHint},共${imported.length}味药材。存在重复药名,请合并剂量或删除多余行`
)
} else {
feedback.msgSuccess(`已导入处方「${row.prescription_name}」${modeHint},共${imported.length}味药材`)
}
feedback.msgSuccess(`已导入处方「${row.prescription_name}」,共${imported.length}味药材`)
showLibraryDialog.value = false
}
watch(showLibraryDialog, (open) => {
if (open) {
librarySearchName.value = ''
librarySearchFormulaType.value = ''
libraryImportMode.value = 'replace'
libraryPage.value = 1
loadLibraryList()
}
@@ -3261,7 +3595,7 @@ async function handlePasteRecipeImport() {
}
pasteRecipeImportLoading.value = true
try {
const resolved: Array<{ name: string; dosage: number }> = []
const resolved: HerbRow[] = []
const skippedNames: string[] = []
for (const row of parsed) {
const name = await resolvePasteHerbNameFromLibrary(row.name)
@@ -3269,7 +3603,7 @@ async function handlePasteRecipeImport() {
skippedNames.push(row.name.trim())
continue
}
resolved.push({ name, dosage: row.dosage })
resolved.push({ name, dosage: row.dosage, formula_type: '主方' })
}
const skippedUnique = [...new Set(skippedNames.filter(Boolean))]
if (resolved.length === 0) {
@@ -3281,7 +3615,8 @@ async function handlePasteRecipeImport() {
return
}
if (pasteRecipeImportMode.value === 'replace') {
editForm.herbs = resolved
const auxKept = editForm.herbs.filter((h) => normalizeFormulaType(h.formula_type) === '辅方')
editForm.herbs = [...auxKept, ...resolved]
} else {
editForm.herbs.push(...resolved)
}
@@ -3306,11 +3641,12 @@ async function handlePasteRecipeImport() {
}
}
// 添加药材
const addHerb = () => {
// 添加药材(主方 / 辅方)
const addHerb = (formulaType: FormulaType = '主方') => {
editForm.herbs.push({
name: '',
dosage: 0
dosage: 0,
formula_type: formulaType
})
}
@@ -3360,6 +3696,8 @@ const resetForm = () => {
editForm.is_system_auto = 0
editForm.business_prescription_audit_rejected = 0
editForm.business_prescription_audit_remark = ''
editForm.times_per_day = 2
Object.assign(editForm.aux_usage, defaultAuxUsage('浓缩水丸'))
clearRxLinkedOrderHint()
}
@@ -3458,7 +3796,7 @@ const handleEdit = async (row: any) => {
editForm.pulse = src.pulse || ''
editForm.pulse_condition = src.pulse_condition || ''
editForm.clinical_diagnosis = src.clinical_diagnosis || ''
editForm.herbs = src.herbs ? JSON.parse(JSON.stringify(src.herbs)) : []
editForm.herbs = src.herbs ? (src.herbs as any[]).map((h) => normalizeHerbRow(h)) : []
editForm.dose_count = src.dose_count ?? 7
editForm.dose_unit = src.dose_unit || '剂'
editForm.usage_days = src.usage_days ?? 7
@@ -3483,6 +3821,10 @@ const handleEdit = async (row: any) => {
editForm.is_system_auto = Number(src.is_system_auto) === 1 ? 1 : 0
editForm.business_prescription_audit_rejected = Number(src.business_prescription_audit_rejected) === 1 ? 1 : 0
editForm.business_prescription_audit_remark = String(src.business_prescription_audit_remark || '')
Object.assign(
editForm.aux_usage,
normalizeAuxUsageForm(src.aux_usage, editForm.prescription_type)
)
// 数据加载完成,重新启用watch
// 使用 setTimeout 确保所有数据都已经渲染完成
@@ -3517,12 +3859,13 @@ const handleSubmit = async () => {
for (let i = 0; i < editForm.herbs.length; i++) {
const herb = editForm.herbs[i]
const label = herbValidationLabel(i)
if (!herb.name || !herb.name.trim()) {
feedback.msgError(`${i + 1}味药材名称不能为空`)
feedback.msgError(`${label}药材名称不能为空`)
return
}
if (!herb.dosage || herb.dosage <= 0) {
feedback.msgError(`${i + 1}味药材剂量必须大于0`)
feedback.msgError(`${label}药材剂量必须大于0`)
return
}
}
@@ -3946,6 +4289,38 @@ onMounted(async () => {
box-sizing: border-box;
}
.rx-herb-section-label {
grid-column: 1 / -1;
font-size: 12px;
font-weight: 600;
color: #409eff;
line-height: 1.4;
}
.rx-herb-section-label--aux {
color: #e6a23c;
margin-top: 4px;
}
.herb-formula-block__head {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
}
.usage-formula-title {
font-size: 13px;
font-weight: 600;
margin: 8px 0 4px;
color: #409eff;
}
.usage-formula-title--aux {
color: #e6a23c;
margin-top: 12px;
}
.rx-herb-cell {
display: grid;
grid-template-columns: 1fr 64px;
@@ -11,6 +11,13 @@
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item class="w-[200px]" label="处方类型">
<el-select v-model="formData.formula_type" placeholder="全部" clearable>
<el-option label="全部" :value="''" />
<el-option label="主方" value="主方" />
<el-option label="辅方" value="辅方" />
</el-select>
</el-form-item>
<el-form-item class="w-[200px]" label="是否公开">
<el-select v-model="formData.is_public" placeholder="全部" clearable>
<el-option label="全部" :value="''" />
@@ -37,6 +44,13 @@
<el-table :data="pager.lists" size="large">
<el-table-column label="ID" prop="id" min-width="60" />
<el-table-column label="处方名称" prop="prescription_name" min-width="200" show-overflow-tooltip />
<el-table-column label="处方类型" min-width="100">
<template #default="{ row }">
<el-tag :type="row.formula_type === '辅方' ? 'warning' : 'primary'" size="small">
{{ row.formula_type || '主方' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="药材数量" min-width="100">
<template #default="{ row }">
{{ row.herbs?.length || 0 }}
@@ -114,6 +128,13 @@
show-word-limit
/>
</el-form-item>
<el-form-item label="处方类型" prop="formula_type">
<el-radio-group v-model="editForm.formula_type">
<el-radio value="主方">主方</el-radio>
<el-radio value="辅方">辅方</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="药材配方" prop="herbs" required>
<div class="w-full">
@@ -200,6 +221,7 @@ import MedicineNameSelect from '@/components/medicine-name-select/index.vue'
// 表单数据
const formData = reactive({
prescription_name: '',
formula_type: '',
is_public: ''
})
@@ -212,6 +234,7 @@ const formRef = ref<FormInstance>()
const editForm = reactive({
id: 0,
prescription_name: '',
formula_type: '主方',
herbs: [] as Array<{ name: string; dosage: number }>,
is_public: 0
})
@@ -267,6 +290,7 @@ const removeHerb = (index: number) => {
const resetForm = () => {
editForm.id = 0
editForm.prescription_name = ''
editForm.formula_type = '主方'
editForm.herbs = []
editForm.is_public = 0
}
@@ -283,6 +307,7 @@ const handleView = (row: any) => {
editMode.value = 'view'
editForm.id = row.id
editForm.prescription_name = row.prescription_name || ''
editForm.formula_type = row.formula_type || '主方'
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
editForm.is_public = row.is_public ?? 0
showEdit.value = true
@@ -293,6 +318,7 @@ const handleEdit = (row: any) => {
editMode.value = 'edit'
editForm.id = row.id
editForm.prescription_name = row.prescription_name || ''
editForm.formula_type = row.formula_type || '主方'
editForm.herbs = row.herbs ? JSON.parse(JSON.stringify(row.herbs)) : []
editForm.is_public = row.is_public ?? 0
showEdit.value = true
@@ -1236,6 +1236,7 @@
<template #header>
<div class="flex items-center gap-2 flex-wrap">
<span class="font-medium text-[15px]">物流轨迹</span>
<span class="text-xs text-gray-400 font-mono">{{ detailData.tracking_number }}</span>
<el-tag
v-if="detailLogisticsUrgent.show"
type="danger"
@@ -2375,17 +2376,43 @@
</div>
</div>
<div class="rx-herbs">
<div v-for="(h, i) in slipHerbsList" :key="i" class="rx-herb-cell">
<span class="rx-herb-name" v-if="prescriptionTabType === 'internal'">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-name" v-else>{{ h.name }}</span>
<span class="rx-herb-total" v-if="prescriptionTabType === 'internal'">{{ rxHerbTotal(h.dosage) }}</span>
<span class="rx-herb-total" v-else>{{ h.dosage }}</span>
</div>
<template v-if="prescriptionTabType === 'internal'">
<template v-if="slipMainHerbs.length">
<div class="rx-herb-section-label">主方</div>
<div
v-for="(h, i) in slipMainHerbs"
:key="'main-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
</template>
<template v-if="slipAuxHerbs.length">
<div class="rx-herb-section-label rx-herb-section-label--aux">辅方</div>
<div
v-for="(h, i) in slipAuxHerbs"
:key="'aux-' + i"
class="rx-herb-cell"
>
<span class="rx-herb-name">{{ h.name }} ({{ h.dosage }})</span>
<span class="rx-herb-total">{{ rxHerbTotal(h.dosage) }}</span>
</div>
</template>
</template>
<template v-else>
<div v-for="(h, i) in slipHerbsList" :key="i" class="rx-herb-cell">
<span class="rx-herb-name">{{ h.name }}</span>
<span class="rx-herb-total">{{ h.dosage }}</span>
</div>
</template>
</div>
</div>
<div class="rx-text">
<p>服法{{ rxUsageText }}</p>
<p v-if="prescriptionTabType === 'internal'">主方服法{{ rxUsageText }}</p>
<p v-else>服法{{ rxUsageText }}</p>
<p v-if="prescriptionTabType === 'internal' && rxAuxUsageText">辅方服法{{ rxAuxUsageText }}</p>
<p v-if="rxAdviceText">医嘱{{ rxAdviceText }}</p>
<p v-if="rxRemarkText">备注{{ rxRemarkText }}</p>
<p v-if="rxPharmacyRemarkText" class="rx-text-warn">
@@ -3812,6 +3839,40 @@ const logisticsTraceLoading = ref(false)
const logisticsTracePayload = ref<Record<string, any> | null>(null)
/** 顺丰/快递100:与运单一致的收件手机后四位(可覆盖订单收货手机) */
const logisticsTracePhoneTail = ref('')
/** 物流轨迹请求序号:同手机多运单或快速切换订单时,丢弃过期的异步响应 */
let logisticsTraceRequestSeq = 0
type LogisticsTraceRequestContext = {
requestSeq: number
orderId: number
trackingNumber: string
}
function bumpLogisticsTraceRequestToken() {
logisticsTraceRequestSeq += 1
logisticsTracePayload.value = null
}
function isCurrentLogisticsTraceContext(ctx: LogisticsTraceRequestContext): boolean {
if (ctx.requestSeq !== logisticsTraceRequestSeq) return false
if (Number(detailData.value?.id) !== ctx.orderId) return false
return String(detailData.value?.tracking_number || '').trim() === ctx.trackingNumber
}
function parseLogisticsTracePayload(
res: unknown,
expectedTrackingNumber: string,
expectedOrderId: number
): Record<string, any> | null {
const raw = (res as { data?: unknown })?.data ?? res
if (!raw || typeof raw !== 'object') return null
const payload = raw as Record<string, any>
const respNum = String(payload.tracking_number || '').trim()
if (respNum && respNum !== expectedTrackingNumber) return null
const respOrderId = Number(payload.order_id)
if (respOrderId > 0 && respOrderId !== expectedOrderId) return null
return payload
}
const detailLogs = ref<any[]>([])
const updateAmountVisible = ref(false)
@@ -3977,24 +4038,33 @@ function expressCompanyLabel(v: unknown) {
}
async function fetchLogisticsTrace() {
const id = Number(detailData.value?.id)
if (!id) return
const orderId = Number(detailData.value?.id)
const trackingNumber = String(detailData.value?.tracking_number || '').trim()
if (!orderId || !trackingNumber) return
const requestSeq = ++logisticsTraceRequestSeq
const ctx: LogisticsTraceRequestContext = { requestSeq, orderId, trackingNumber }
logisticsTraceLoading.value = true
try {
const digits = String(logisticsTracePhoneTail.value || '').replace(/\D/g, '')
const params: { id: number; express_company?: string; phone_tail?: string } = {
id,
id: orderId,
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>
if (!isCurrentLogisticsTraceContext(ctx)) return
logisticsTracePayload.value = parseLogisticsTracePayload(res, trackingNumber, orderId)
} catch {
if (!isCurrentLogisticsTraceContext(ctx)) return
logisticsTracePayload.value = null
} finally {
logisticsTraceLoading.value = false
if (isCurrentLogisticsTraceContext(ctx)) {
logisticsTraceLoading.value = false
}
}
}
@@ -4120,7 +4190,7 @@ async function openDetail(id: number) {
// Bug
detailData.value = null
detailUnlinkedPayOrders.value = []
logisticsTracePayload.value = null
bumpLogisticsTraceRequestToken()
detailLogisticsExpress.value = 'auto'
logisticsTracePhoneTail.value = ''
detailLogs.value = []
@@ -4981,35 +5051,47 @@ const completeOrderDialogVisible = ref(false)
const completeOrderId = ref(0)
const completeFulfillmentStatus = ref<number>(3)
const completeOrderSubmitting = ref(false)
let completeOrderLogisticsRequestSeq = 0
function onCompleteOrderDialogClosed() {
completeOrderId.value = 0
completeOrderLogisticsRequestSeq += 1
completeOrderLogisticsPayload.value = null
completeOrderLogisticsLoading.value = false
}
async function fetchCompleteOrderLogisticsForDialog(row: {
id: number
tracking_number?: unknown
express_company?: unknown
recipient_phone?: unknown
}) {
const orderId = Number(row.id)
const trackingNumber = String(row.tracking_number || '').trim()
if (!orderId || !trackingNumber) return
const requestSeq = ++completeOrderLogisticsRequestSeq
completeOrderLogisticsLoading.value = true
completeOrderLogisticsPayload.value = null
try {
const digits = String(row.recipient_phone || '').replace(/\D/g, '')
const params: { id: number; express_company?: string; phone_tail?: string } = {
id: row.id,
id: orderId,
express_company: String(row.express_company || 'auto') || 'auto'
}
if (digits.length >= 4) {
params.phone_tail = digits
}
const res: any = await prescriptionOrderLogisticsTrace(params)
completeOrderLogisticsPayload.value = (res?.data ?? res) as Record<string, any>
if (requestSeq !== completeOrderLogisticsRequestSeq || completeOrderId.value !== orderId) return
completeOrderLogisticsPayload.value = parseLogisticsTracePayload(res, trackingNumber, orderId)
} catch {
if (requestSeq !== completeOrderLogisticsRequestSeq || completeOrderId.value !== orderId) return
completeOrderLogisticsPayload.value = null
} finally {
completeOrderLogisticsLoading.value = false
if (requestSeq === completeOrderLogisticsRequestSeq && completeOrderId.value === orderId) {
completeOrderLogisticsLoading.value = false
}
}
}
@@ -5272,12 +5354,116 @@ const prescriptionTabType = ref('internal')
const prescriptionSlipPrintRef = ref<HTMLElement | null>(null)
const prescriptionSlipExporting = ref(false)
type SlipFormulaType = '主方' | '辅方'
type SlipAuxUsageForm = {
dosage_amount?: number
dosage_bag_count: number
need_decoction: boolean
bags_per_dose: number
times_per_day: number
usage_days: number
}
function normalizeSlipFormulaType(v: unknown): SlipFormulaType {
return v === '辅方' ? '辅方' : '主方'
}
function defaultSlipAuxUsage(prescriptionType = '浓缩水丸'): SlipAuxUsageForm {
if (prescriptionType === '饮片') {
return {
dosage_amount: 50,
dosage_bag_count: 1,
need_decoction: false,
bags_per_dose: 1,
times_per_day: 3,
usage_days: 7
}
}
if (prescriptionType === '浓缩水丸') {
return {
dosage_amount: 5,
dosage_bag_count: 1,
need_decoction: false,
bags_per_dose: 1,
times_per_day: 3,
usage_days: 7
}
}
return {
dosage_amount: 1,
dosage_bag_count: 1,
need_decoction: false,
bags_per_dose: 1,
times_per_day: 3,
usage_days: 7
}
}
function normalizeSlipAuxUsageForm(raw: unknown, prescriptionType: string): SlipAuxUsageForm {
const base = defaultSlipAuxUsage(prescriptionType)
if (!raw || typeof raw !== 'object') return { ...base }
const o = raw as Record<string, unknown>
return {
dosage_amount:
o.dosage_amount !== null && o.dosage_amount !== undefined && o.dosage_amount !== ''
? Number(o.dosage_amount)
: base.dosage_amount,
dosage_bag_count: o.dosage_bag_count != null ? Number(o.dosage_bag_count) || 1 : base.dosage_bag_count,
need_decoction: o.need_decoction === 1 || o.need_decoction === true,
bags_per_dose: o.bags_per_dose != null ? Number(o.bags_per_dose) || 1 : base.bags_per_dose,
times_per_day: o.times_per_day != null ? Number(o.times_per_day) || 3 : base.times_per_day,
usage_days: o.usage_days != null ? Number(o.usage_days) || 7 : base.usage_days
}
}
function buildSlipUsageSegmentText(
usage: {
prescription_type?: string
dosage_amount?: number | null
dosage_unit?: string
dosage_bag_count?: number
times_per_day?: number
usage_way?: string
usage_time?: string
},
fallbackWay?: string,
fallbackTime?: string
): string {
const pt = usage.prescription_type || '浓缩水丸'
const times = Number(usage.times_per_day) > 0 ? Number(usage.times_per_day) : 3
const amount = usage.dosage_amount != null ? Number(usage.dosage_amount) : 10
const unit = usage.dosage_unit || (pt === '饮片' ? 'ml' : 'g')
const usageWay = usage.usage_way || fallbackWay || '温水送服'
const usageTime = usage.usage_time || fallbackTime || ''
const seg: string[] = []
seg.push(`每天${times}`)
if (pt === '浓缩水丸') {
const bags = Number(usage.dosage_bag_count) > 0 ? Number(usage.dosage_bag_count) : 1
seg.push(`一次${bags}`)
seg.push(`每袋${amount}${unit}`)
} else {
seg.push(`一次${amount}${unit}`)
}
seg.push(usageWay)
if (usageTime) seg.push(usageTime)
return seg.join(', ')
}
//
const slipHerbsList = computed(() => {
const h = prescriptionViewData.value?.herbs
return Array.isArray(h) ? h : []
})
const slipMainHerbs = computed(() =>
slipHerbsList.value.filter((h: any) => normalizeSlipFormulaType(h?.formula_type) === '主方')
)
const slipAuxHerbs = computed(() =>
slipHerbsList.value.filter((h: any) => normalizeSlipFormulaType(h?.formula_type) === '辅方')
)
const slipDietaryText = computed(() => {
const d = prescriptionViewData.value?.dietary_taboo
if (Array.isArray(d)) return d.filter(Boolean).join('、')
@@ -5404,23 +5590,26 @@ const rxUsageText = computed(() => {
const v = prescriptionViewData.value as any
if (!v) return '—'
if (v.usage_text) return v.usage_text
const times = Number(v.times_per_day) > 0 ? Number(v.times_per_day) : 3
const amount = v.dosage_amount != null ? Number(v.dosage_amount) : 10
const unit = v.dosage_unit || 'g'
const usageWay = v.usage_way || '温水送服'
const usageTime = v.usage_time || ''
const seg: string[] = []
seg.push(`每天${times}`)
if ((v.prescription_type || '浓缩水丸') === '浓缩水丸') {
const bags = Number(v.dosage_bag_count) > 0 ? Number(v.dosage_bag_count) : 1
seg.push(`一次${bags}`)
seg.push(`每袋${amount}${unit}`)
} else {
seg.push(`一次${amount}${unit}`)
}
seg.push(usageWay)
if (usageTime) seg.push(usageTime)
return seg.join(', ')
return buildSlipUsageSegmentText(v)
})
const rxAuxUsageText = computed(() => {
const v = prescriptionViewData.value as any
if (!v || !slipAuxHerbs.value.length) return ''
const aux = normalizeSlipAuxUsageForm(v.aux_usage, v.prescription_type || '浓缩水丸')
return buildSlipUsageSegmentText(
{
prescription_type: v.prescription_type,
dosage_amount: aux.dosage_amount,
dosage_unit: v.dosage_unit,
dosage_bag_count: aux.dosage_bag_count,
times_per_day: aux.times_per_day,
usage_way: v.usage_way,
usage_time: v.usage_time
},
v.usage_way,
v.usage_time
)
})
/** 出丸:优先用 slipPillGrams(每袋用量×袋数×每天次数×服用天数),否则按药材总量×剂数 */
@@ -6223,6 +6412,19 @@ async function downloadPrescriptionSlipPdf() {
box-sizing: border-box;
}
.rx-herb-section-label {
grid-column: 1 / -1;
font-size: 12px;
font-weight: 600;
color: #409eff;
line-height: 1.4;
}
.rx-herb-section-label--aux {
color: #e6a23c;
margin-top: 4px;
}
.rx-herb-cell {
display: grid;
grid-template-columns: 1fr 64px;
@@ -3440,6 +3440,40 @@ const logisticsTraceLoading = ref(false)
const logisticsTracePayload = ref<Record<string, any> | null>(null)
/** 顺丰/快递100:与运单一致的收件手机后四位(可覆盖订单收货手机) */
const logisticsTracePhoneTail = ref('')
/** 物流轨迹请求序号:同手机多运单或快速切换订单时,丢弃过期的异步响应 */
let logisticsTraceRequestSeq = 0
type LogisticsTraceRequestContext = {
requestSeq: number
orderId: number
trackingNumber: string
}
function bumpLogisticsTraceRequestToken() {
logisticsTraceRequestSeq += 1
logisticsTracePayload.value = null
}
function isCurrentLogisticsTraceContext(ctx: LogisticsTraceRequestContext): boolean {
if (ctx.requestSeq !== logisticsTraceRequestSeq) return false
if (Number(detailData.value?.id) !== ctx.orderId) return false
return String(detailData.value?.tracking_number || '').trim() === ctx.trackingNumber
}
function parseLogisticsTracePayload(
res: unknown,
expectedTrackingNumber: string,
expectedOrderId: number
): Record<string, any> | null {
const raw = (res as { data?: unknown })?.data ?? res
if (!raw || typeof raw !== 'object') return null
const payload = raw as Record<string, any>
const respNum = String(payload.tracking_number || '').trim()
if (respNum && respNum !== expectedTrackingNumber) return null
const respOrderId = Number(payload.order_id)
if (respOrderId > 0 && respOrderId !== expectedOrderId) return null
return payload
}
const detailLogs = ref<any[]>([])
const updateAmountVisible = ref(false)
@@ -3534,24 +3568,33 @@ function expressCompanyLabel(v: unknown) {
}
async function fetchLogisticsTrace() {
const id = Number(detailData.value?.id)
if (!id) return
const orderId = Number(detailData.value?.id)
const trackingNumber = String(detailData.value?.tracking_number || '').trim()
if (!orderId || !trackingNumber) return
const requestSeq = ++logisticsTraceRequestSeq
const ctx: LogisticsTraceRequestContext = { requestSeq, orderId, trackingNumber }
logisticsTraceLoading.value = true
try {
const digits = String(logisticsTracePhoneTail.value || '').replace(/\D/g, '')
const params: { id: number; express_company?: string; phone_tail?: string } = {
id,
id: orderId,
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>
if (!isCurrentLogisticsTraceContext(ctx)) return
logisticsTracePayload.value = parseLogisticsTracePayload(res, trackingNumber, orderId)
} catch {
if (!isCurrentLogisticsTraceContext(ctx)) return
logisticsTracePayload.value = null
} finally {
logisticsTraceLoading.value = false
if (isCurrentLogisticsTraceContext(ctx)) {
logisticsTraceLoading.value = false
}
}
}
@@ -3677,7 +3720,7 @@ async function openDetail(id: number) {
// Bug
detailData.value = null
detailUnlinkedPayOrders.value = []
logisticsTracePayload.value = null
bumpLogisticsTraceRequestToken()
detailLogisticsExpress.value = 'auto'
logisticsTracePhoneTail.value = ''
detailLogs.value = []
@@ -3693,7 +3736,7 @@ async function openDetail(id: number) {
const dig = String(d.recipient_phone || '').replace(/\D/g, '')
logisticsTracePhoneTail.value = dig.length >= 4 ? dig : ''
if (String(d.tracking_number || '').trim()) {
fetchLogisticsTrace()
void fetchLogisticsTrace()
}
fetchLogs(id)
@@ -0,0 +1,82 @@
<template>
<el-select
:model-value="modelValue"
:placeholder="placeholder"
:clearable="clearable"
:filterable="filterable"
:allow-create="allowCreate"
:default-first-option="allowCreate"
:disabled="disabled"
:loading="loading"
:class="selectClass"
:style="selectStyle"
@update:model-value="emit('update:modelValue', $event)"
@change="emit('change', $event)"
@visible-change="onVisibleChange"
>
<el-option
v-for="item in normalizedOptions"
:key="item.name"
:label="item.name"
:value="item.name"
/>
<!-- 旧记录可能存在不在当前字典内的值保留显示避免编辑时反查不到 -->
<el-option
v-if="modelValue && !hasCurrentValue"
:key="`__legacy_${modelValue}`"
:label="`${modelValue}(已停用)`"
:value="modelValue"
/>
</el-select>
</template>
<script lang="ts" setup>
interface OptionItem {
name: string
value?: string
}
const props = withDefaults(
defineProps<{
modelValue?: string
options: Array<OptionItem | string>
loading?: boolean
placeholder?: string
clearable?: boolean
filterable?: boolean
allowCreate?: boolean
disabled?: boolean
selectClass?: string
selectStyle?: string | Record<string, string>
}>(),
{
modelValue: '',
loading: false,
placeholder: '请选择自媒体来源',
clearable: true,
filterable: true,
allowCreate: false,
disabled: false,
}
)
const emit = defineEmits<{
'update:modelValue': [value: string]
change: [value: string]
'visible-change': [visible: boolean]
}>()
const normalizedOptions = computed<OptionItem[]>(() => {
return (props.options || []).map((item) =>
typeof item === 'string' ? { name: item } : { name: item.name, value: item.value }
)
})
const hasCurrentValue = computed(() => {
return normalizedOptions.value.some((item) => item.name === props.modelValue)
})
const onVisibleChange = (visible: boolean) => {
emit('visible-change', visible)
}
</script>
@@ -0,0 +1,254 @@
<template>
<div class="personal-account-cost-page">
<el-card class="!border-none mb-4" shadow="never">
<div class="flex flex-wrap">
<div class="w-1/2 md:w-1/3">
<div class="leading-10">当前筛选天数</div>
<div class="text-4xl">{{ pager.extend.days_count ?? 0 }}</div>
</div>
<div class="w-1/2 md:w-1/3">
<div class="leading-10">累计账户消耗 ()</div>
<div class="text-4xl">¥{{ pager.extend.total_amount ?? '0.00' }}</div>
</div>
</div>
</el-card>
<el-card class="!border-none" shadow="never">
<el-form class="mb-[-16px]" :model="queryParams" inline>
<el-form-item label="日期范围">
<daterange-picker
v-model:startTime="queryParams.start_date"
v-model:endTime="queryParams.end_date"
/>
</el-form-item>
<el-form-item label="部门">
<el-tree-select
v-model="queryParams.dept_id"
:data="deptOptions"
node-key="id"
:props="deptTreeProps"
:default-expand-all="true"
check-strictly
placeholder="全部部门"
clearable
filterable
class="w-[220px]"
@change="resetPage"
/>
</el-form-item>
<el-form-item label="自媒体来源">
<media-source-select
v-model="queryParams.media_source"
:options="mediaSourceOptions"
:loading="mediaSourceLoading"
placeholder="全部来源"
:allow-create="false"
select-class="w-[220px]"
@change="resetPage"
@visible-change="onMediaSourceDropdownVisible"
/>
</el-form-item>
<el-form-item class="w-[280px]" label="备注/录入人">
<el-input
v-model="queryParams.remark"
placeholder="备注 / 创建人"
clearable
@keyup.enter="resetPage"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="resetPage">查询</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button v-if="selfInputPath" class="ml-2" @click="goSelfInput">返回统计</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="!border-none mt-4" shadow="never">
<div>
<el-button v-perms="['stats.personal_account_cost/add']" type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增
</el-button>
</div>
<el-table class="mt-4" size="large" v-loading="pager.loading" :data="pager.lists">
<el-table-column label="日期" prop="cost_date" min-width="120" />
<el-table-column label="自媒体来源" prop="media_source" min-width="160" show-overflow-tooltip />
<el-table-column label="账户消耗" min-width="120">
<template #default="{ row }">¥{{ row.amount }}</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="200" show-overflow-tooltip />
<el-table-column label="录入人" prop="creator_name" min-width="100" />
<el-table-column label="部门" prop="dept_name" min-width="140">
<template #default="{ row }">
<el-tooltip
v-if="row.dept_path"
:content="row.dept_path"
placement="top"
effect="dark"
>
<span class="dept-cell">{{ row.dept_name || '未分配' }}</span>
</el-tooltip>
<span v-else-if="row.dept_name">{{ row.dept_name }}</span>
<span v-else class="text-gray-400">未分配</span>
</template>
</el-table-column>
<el-table-column label="最后修改人" prop="updater_name" min-width="100" />
<el-table-column label="更新时间" prop="update_time" min-width="180" />
<el-table-column label="操作" width="160" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['stats.personal_account_cost/edit']"
type="primary"
link
@click="handleEdit(row)"
>
编辑
</el-button>
<el-button
v-perms="['stats.personal_account_cost/delete']"
type="danger"
link
@click="handleDelete(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="getLists" />
</div>
</el-card>
<cost-edit-popup
v-if="showEdit"
ref="editRef"
:media-source-options="mediaSourceOptions"
:media-source-loading="mediaSourceLoading"
@success="handleCostSuccess"
@close="showEdit = false"
/>
</div>
</template>
<script lang="ts" setup name="personalAccountCost">
import { personalAccountCostDelete, personalAccountCostLists } from '@/api/self_input_stats'
import { deptAll } from '@/api/org/department'
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'
import feedback from '@/utils/feedback'
import CostEditPopup from './cost-edit.vue'
import MediaSourceSelect from './MediaSourceSelect.vue'
import { useMediaSourceOptions } from './useMediaSourceOptions'
const router = useRouter()
const editRef = shallowRef<InstanceType<typeof CostEditPopup>>()
const showEdit = ref(false)
const deptOptions = ref<any[]>([])
const {
mediaSourceOptions,
mediaSourceLoading,
loadMediaSourceOptions,
refreshMediaSourceOptions,
} = useMediaSourceOptions()
const deptTreeProps = {
value: 'id',
label: 'name',
children: 'children',
}
const selfInputPath = computed(() => getRoutePath('stats.self_input/overview') || '')
const goSelfInput = () => {
if (selfInputPath.value) {
router.push(selfInputPath.value)
}
}
const queryParams = reactive({
start_date: '',
end_date: '',
media_source: '',
dept_id: undefined as number | undefined,
remark: '',
})
const { pager, getLists, resetPage } = usePaging({
fetchFun: personalAccountCostLists,
params: queryParams,
})
const handleReset = () => {
queryParams.start_date = ''
queryParams.end_date = ''
queryParams.media_source = ''
queryParams.dept_id = undefined
queryParams.remark = ''
resetPage()
}
const onMediaSourceDropdownVisible = (visible: boolean) => {
if (visible) {
refreshMediaSourceOptions()
}
}
const handleCostSuccess = async () => {
await refreshMediaSourceOptions()
getLists()
}
const handleAdd = async () => {
await refreshMediaSourceOptions()
showEdit.value = true
await nextTick()
editRef.value?.open('add')
}
const handleEdit = async (row: Record<string, any>) => {
showEdit.value = true
await nextTick()
editRef.value?.open('edit')
editRef.value?.setFormData(row)
}
const handleDelete = async (id: number) => {
await feedback.confirm('确定删除该账户消耗记录?')
await personalAccountCostDelete({ id })
getLists()
}
const loadDeptOptions = async () => {
try {
const res = await deptAll({ apply_data_scope: 1 })
if (Array.isArray(res)) {
deptOptions.value = res
}
} catch (e) {
deptOptions.value = []
}
}
onMounted(() => {
loadDeptOptions()
loadMediaSourceOptions()
})
</script>
<style scoped lang="scss">
.personal-account-cost-page {
padding: 20px;
}
.dept-cell {
cursor: help;
border-bottom: 1px dashed #c0c4cc;
}
</style>
@@ -0,0 +1,142 @@
<template>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="520px"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-form-item label="日期" prop="cost_date">
<el-date-picker
v-model="formData.cost_date"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
:disabled="mode === 'edit'"
class="w-full"
/>
</el-form-item>
<el-form-item label="自媒体来源" prop="media_source">
<media-source-select
v-model="formData.media_source"
:options="mediaSourceOptions"
:loading="mediaSourceLoading"
placeholder="请选择自媒体来源"
:allow-create="false"
:disabled="mode === 'edit'"
select-class="w-full"
/>
</el-form-item>
<el-form-item label="账户消耗" prop="amount">
<el-input-number
v-model="formData.amount"
:min="0"
:step="0.01"
:precision="2"
class="w-full"
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="formData.remark"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
maxlength="255"
show-word-limit
placeholder="选填"
/>
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import {
personalAccountCostAdd,
personalAccountCostEdit,
} from '@/api/self_input_stats'
import Popup from '@/components/popup/index.vue'
import MediaSourceSelect from './MediaSourceSelect.vue'
import type { MediaSourceOption } from './useMediaSourceOptions'
withDefaults(
defineProps<{
mediaSourceOptions?: MediaSourceOption[]
mediaSourceLoading?: boolean
}>(),
{
mediaSourceOptions: () => [],
mediaSourceLoading: false,
}
)
const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>()
const popupRef = shallowRef<InstanceType<typeof Popup>>()
const mode = ref<'add' | 'edit'>('add')
const popupTitle = computed(() => (mode.value === 'edit' ? '编辑账户消耗' : '新增账户消耗'))
const formData = reactive({
id: '',
cost_date: '',
media_source: '',
amount: 0,
remark: '',
})
const formRules = {
cost_date: [{ required: true, message: '请选择日期', trigger: ['change'] }],
media_source: [{ required: true, message: '请填写自媒体来源', trigger: ['blur'] }],
amount: [{ required: true, message: '请输入账户消耗金额', trigger: ['blur', 'change'] }],
}
const resetForm = () => {
formData.id = ''
formData.cost_date = ''
formData.media_source = ''
formData.amount = 0
formData.remark = ''
}
const handleSubmit = async () => {
await formRef.value?.validate()
if (mode.value === 'edit') {
await personalAccountCostEdit(formData)
} else {
await personalAccountCostAdd(formData)
}
popupRef.value?.close()
emit('success')
}
const open = (type: 'add' | 'edit' = 'add') => {
mode.value = type
resetForm()
popupRef.value?.open()
}
const setFormData = (data: Record<string, any>) => {
formData.id = data.id ?? ''
formData.cost_date = data.cost_date ?? ''
formData.media_source = data.media_source ?? ''
formData.amount = Number(data.amount ?? 0)
formData.remark = data.remark ?? ''
}
const handleClose = () => {
emit('close')
}
defineExpose({
open,
setFormData,
})
</script>
+499
View File
@@ -0,0 +1,499 @@
<template>
<div class="self-input-stats-page">
<el-card class="!border-none" shadow="never">
<el-form :inline="true" :model="queryParams" class="stats-filter-form">
<el-form-item label="时间范围">
<el-radio-group v-model="queryParams.time_type" @change="handleTimeTypeChange">
<el-radio-button label="today">今天</el-radio-button>
<el-radio-button label="yesterday">昨天</el-radio-button>
<el-radio-button label="week">最近7天</el-radio-button>
<el-radio-button label="month">最近30天</el-radio-button>
<el-radio-button label="custom">自定义</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item v-if="queryParams.time_type === 'custom'">
<el-date-picker
v-model="dateRange"
type="daterange"
value-format="YYYY-MM-DD"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 260px"
@change="handleCustomDateChange"
/>
</el-form-item>
<el-form-item label="部门">
<el-tree-select
v-model="queryParams.dept_id"
:data="deptOptions"
node-key="id"
:props="deptTreeProps"
:default-expand-all="true"
check-strictly
placeholder="全部部门"
clearable
filterable
style="width: 220px"
@change="handleQuery"
/>
</el-form-item>
<el-form-item label="自媒体来源">
<media-source-select
v-model="queryParams.media_source"
:options="mediaSourceOptions"
:loading="mediaSourceLoading"
placeholder="全部来源"
:allow-create="false"
select-style="width: 220px"
@change="handleQuery"
@visible-change="onMediaSourceDropdownVisible"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="pager.loading" @click="handleQuery">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<div class="stats-kpi-grid">
<div v-for="card in visibleSummaryCards" :key="card.key" class="stats-kpi-card">
<div class="stats-kpi-label">{{ card.label }}</div>
<div class="stats-kpi-value" :class="{ 'is-money': card.type === 'money' }">
{{ renderMetric(card.key, overview.summary, card.type) }}
</div>
</div>
</div>
<el-card class="!border-none mt-4 stats-detail-card" shadow="never">
<template #header>
<div class="card-header">
<div class="card-header-main">
<span class="card-title">业绩明细</span>
<span class="card-hint">{{ dateRangeText }}</span>
</div>
<div class="card-header-actions">
<el-button v-perms="['stats.personal_yeji/add']" type="primary" @click="handleAddYeji">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增业绩
</el-button>
<el-button
v-if="accountCostEntryPath"
v-perms="['stats.personal_account_cost/lists']"
@click="goAccountCostEntry"
>
账户消耗录入
</el-button>
</div>
</div>
</template>
<el-table
v-loading="pager.loading"
:data="pager.lists"
border
size="large"
max-height="640"
>
<el-table-column label="日期" prop="yeji_date" min-width="110" fixed="left" />
<el-table-column label="自媒体来源" prop="media_source" min-width="140" show-overflow-tooltip />
<el-table-column label="录入人" prop="creator_name" min-width="100" />
<el-table-column label="部门" prop="dept_name" min-width="140">
<template #default="{ row }">
<el-tooltip
v-if="row.dept_path"
:content="row.dept_path"
placement="top"
effect="dark"
>
<span class="dept-cell">{{ row.dept_name || '未分配' }}</span>
</el-tooltip>
<span v-else-if="row.dept_name">{{ row.dept_name }}</span>
<span v-else class="text-gray-400">未分配</span>
</template>
</el-table-column>
<el-table-column
v-for="col in visibleTableColumns"
:key="col.key"
:label="col.label"
:min-width="col.minWidth || 100"
align="right"
>
<template #default="{ row }">
{{ renderMetric(col.key, row, col.type) }}
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="160" show-overflow-tooltip />
<el-table-column label="操作" width="140" fixed="right">
<template #default="{ row }">
<el-button
v-perms="['stats.personal_yeji/edit']"
type="primary"
link
@click="handleEditYeji(row)"
>
编辑
</el-button>
<el-button
v-perms="['stats.personal_yeji/delete']"
type="danger"
link
@click="handleDeleteYeji(row.id)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end mt-4">
<pagination v-model="pager" @change="fetchOverview" />
</div>
</el-card>
<yeji-edit-popup
v-if="showYejiEdit"
ref="yejiEditRef"
:media-source-options="mediaSourceOptions"
:media-source-loading="mediaSourceLoading"
@success="handleYejiSuccess"
@close="showYejiEdit = false"
/>
</div>
</template>
<script lang="ts" setup name="selfInputStats">
import {
getSelfInputOverview,
personalYejiDelete,
} from '@/api/self_input_stats'
import { deptAll } from '@/api/org/department'
import { usePaging } from '@/hooks/usePaging'
import { getRoutePath } from '@/router'
import feedback from '@/utils/feedback'
import MediaSourceSelect from './MediaSourceSelect.vue'
import YejiEditPopup from './yeji-edit.vue'
import { useMediaSourceOptions } from './useMediaSourceOptions'
type MetricType = 'count' | 'money' | 'percent' | 'ratio'
interface MetricCard {
key: string
label: string
type: MetricType
}
interface MetricColumn {
key: string
label: string
type: MetricType
minWidth?: number
}
const router = useRouter()
const yejiEditRef = shallowRef<InstanceType<typeof YejiEditPopup>>()
const showYejiEdit = ref(false)
const dateRange = ref<string[]>([])
const deptOptions = ref<any[]>([])
const {
mediaSourceOptions,
mediaSourceLoading,
loadMediaSourceOptions,
refreshMediaSourceOptions,
} = useMediaSourceOptions()
const deptTreeProps = {
value: 'id',
label: 'name',
children: 'children',
}
const overview = reactive<Record<string, any>>({
date_range: [],
summary: {},
can_view_finance: false,
})
const FINANCE_KEYS = new Set(['account_cost', 'cash_cost', 'roi'])
const canViewFinance = computed(() => Boolean(overview.can_view_finance))
const queryParams = reactive({
media_source: '',
dept_id: undefined as number | undefined,
time_type: 'today',
start_date: '',
end_date: '',
})
const accountCostEntryPath = computed(() => getRoutePath('stats.personal_account_cost/lists') || '')
const goAccountCostEntry = () => {
if (accountCostEntryPath.value) {
router.push(accountCostEntryPath.value)
}
}
const fetchOverviewList = async (params: Record<string, any>) => {
if (queryParams.time_type === 'custom') {
params.start_date = dateRange.value[0] || ''
params.end_date = dateRange.value[1] || ''
}
const res = await getSelfInputOverview(params)
Object.assign(overview, res?.extend || {})
return res
}
const loadDeptOptions = async () => {
try {
const res = await deptAll({ apply_data_scope: 1 })
if (Array.isArray(res)) {
deptOptions.value = res
}
} catch (e) {
deptOptions.value = []
}
}
const onMediaSourceDropdownVisible = (visible: boolean) => {
if (visible) {
refreshMediaSourceOptions()
}
}
const handleYejiSuccess = async () => {
await refreshMediaSourceOptions()
await fetchOverview()
}
onMounted(() => {
loadDeptOptions()
loadMediaSourceOptions()
})
const { pager, getLists } = usePaging({
fetchFun: fetchOverviewList,
params: queryParams,
firstLoading: true,
})
const summaryCards: MetricCard[] = [
{ key: 'add_fans_count', label: '加粉数', type: 'count' },
{ key: 'total_open_count', label: '总开口', type: 'count' },
{ key: 'unreplied_count', label: '未回复', type: 'count' },
{ key: 'paid_appointment_count', label: '付费挂号', type: 'count' },
{ key: 'free_appointment_count', label: '免费挂号', type: 'count' },
{ key: 'interview_count', label: '面诊', type: 'count' },
{ key: 'order_amount', label: '订单金额', type: 'money' },
{ key: 'account_cost', label: '账户消耗', type: 'money' },
{ key: 'paid_appointment_rate', label: '付费挂号率', type: 'percent' },
{ key: 'interview_rate', label: '面诊率', type: 'percent' },
{ key: 'receive_rate', label: '接诊率', type: 'percent' },
{ key: 'interview_receive_rate', label: '面诊接诊率', type: 'percent' },
{ key: 'avg_unit_price', label: '平均单价', type: 'money' },
{ key: 'cash_cost', label: '现金成本', type: 'money' },
{ key: 'roi', label: 'ROI', type: 'ratio' },
]
const tableColumns: MetricColumn[] = [
{ key: 'add_fans_count', label: '加粉数', type: 'count' },
{ key: 'total_open_count', label: '总开口', type: 'count' },
{ key: 'unreplied_count', label: '未回复', type: 'count' },
{ key: 'paid_appointment_count', label: '付费挂号', type: 'count' },
{ key: 'free_appointment_count', label: '免费挂号', type: 'count' },
{ key: 'appointment_total_count', label: '挂号总数', type: 'count' },
{ key: 'interview_count', label: '面诊', type: 'count' },
{ key: 'completed_order_count', label: '接诊诊单', type: 'count' },
{ key: 'order_amount', label: '订单金额', type: 'money', minWidth: 110 },
{ key: 'account_cost', label: '账户消耗', type: 'money', minWidth: 110 },
{ key: 'paid_appointment_rate', label: '付费挂号率', type: 'percent', minWidth: 110 },
{ key: 'open_appointment_rate', label: '开口挂号率', type: 'percent', minWidth: 110 },
{ key: 'interview_rate', label: '面诊率', type: 'percent', minWidth: 100 },
{ key: 'receive_rate', label: '接诊率', type: 'percent', minWidth: 100 },
{ key: 'interview_receive_rate', label: '面诊接诊率', type: 'percent', minWidth: 120 },
{ key: 'open_receive_rate', label: '开口接诊率', type: 'percent', minWidth: 110 },
{ key: 'avg_unit_price', label: '平均单价', type: 'money', minWidth: 100 },
{ key: 'cash_cost', label: '现金成本', type: 'money', minWidth: 100 },
{ key: 'roi', label: 'ROI', type: 'ratio', minWidth: 80 },
]
const visibleSummaryCards = computed(() =>
canViewFinance.value
? summaryCards
: summaryCards.filter((card) => !FINANCE_KEYS.has(card.key))
)
const visibleTableColumns = computed(() =>
canViewFinance.value
? tableColumns
: tableColumns.filter((col) => !FINANCE_KEYS.has(col.key))
)
const dateRangeText = computed(() => {
if (!overview.date_range?.length) return '未选择'
return `${overview.date_range[0]}${overview.date_range[1]}`
})
const fetchOverview = async () => {
try {
await getLists()
} catch (error: any) {
console.error('获取自录转化统计失败:', error)
ElMessage.error(error?.msg || '获取统计数据失败')
}
}
const handleTimeTypeChange = () => {
if (queryParams.time_type !== 'custom') {
dateRange.value = []
pager.page = 1
fetchOverview()
}
}
const handleCustomDateChange = () => {
if (dateRange.value.length === 2) {
pager.page = 1
fetchOverview()
}
}
const handleQuery = () => {
pager.page = 1
fetchOverview()
}
const handleReset = () => {
queryParams.media_source = ''
queryParams.dept_id = undefined
queryParams.time_type = 'today'
dateRange.value = []
pager.page = 1
pager.size = 15
fetchOverview()
}
const renderMetric = (key: string, source: Record<string, any>, type = 'count') => {
const value = source?.[key] ?? 0
if (type === 'money') return `¥${Number(value || 0).toFixed(2)}`
if (type === 'percent') return `${Number(value || 0).toFixed(2)}%`
if (type === 'ratio') return Number(value || 0).toFixed(2)
return String(value ?? 0)
}
const handleAddYeji = async () => {
await refreshMediaSourceOptions()
showYejiEdit.value = true
await nextTick()
yejiEditRef.value?.open('add')
}
const handleEditYeji = async (row: Record<string, any>) => {
showYejiEdit.value = true
await nextTick()
yejiEditRef.value?.open('edit')
yejiEditRef.value?.setFormData(row)
}
const handleDeleteYeji = async (id: number) => {
await feedback.confirm('确定删除该业绩记录?')
await personalYejiDelete({ id })
fetchOverview()
}
onMounted(async () => {
await fetchOverview()
})
</script>
<style scoped lang="scss">
.self-input-stats-page {
padding: 20px;
}
.stats-filter-form {
:deep(.el-form-item) {
margin-bottom: 0;
}
}
.stats-kpi-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
gap: 16px;
margin-top: 16px;
}
.stats-kpi-card {
background: linear-gradient(145deg, #ffffff, #f5f8ff);
border: 1px solid #ebf1ff;
border-radius: 14px;
padding: 18px 16px;
box-shadow: 0 10px 24px rgba(74, 120, 255, 0.08);
}
.dept-cell {
cursor: help;
border-bottom: 1px dashed #c0c4cc;
}
.stats-kpi-label {
color: #6b7280;
font-size: 13px;
}
.stats-kpi-value {
margin-top: 12px;
font-size: 28px;
line-height: 1.1;
font-weight: 700;
color: #1f2937;
}
.stats-kpi-value.is-money {
font-size: 24px;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.card-header-main {
display: flex;
align-items: baseline;
gap: 10px;
}
.card-header-actions {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.card-title {
font-size: 15px;
font-weight: 600;
color: #1f2937;
}
.card-hint {
color: #909399;
font-size: 12px;
}
.stats-detail-card :deep(.el-card__body) {
padding-top: 0;
}
</style>
@@ -0,0 +1,63 @@
import { getSelfInputMediaSourceOptions } from '@/api/self_input_stats'
/**
* 自录转化统计:自媒体来源选项(来自字典「推广渠道」channels)。
* 业绩页与账户消耗页共用同一接口,下拉打开时刷新,保证两侧字典变更同步。
*/
export interface MediaSourceOption {
name: string
value: string
}
export function useMediaSourceOptions() {
const mediaSourceOptions = ref<MediaSourceOption[]>([])
const mediaSourceLoading = ref(false)
const normalize = (raw: any): MediaSourceOption[] => {
if (!Array.isArray(raw)) return []
const list: MediaSourceOption[] = []
const seen = new Set<string>()
for (const item of raw) {
if (typeof item === 'string') {
const name = item.trim()
if (name && !seen.has(name)) {
seen.add(name)
list.push({ name, value: '' })
}
continue
}
if (item && typeof item === 'object') {
const name = String(item.name ?? '').trim()
if (name && !seen.has(name)) {
seen.add(name)
list.push({ name, value: String(item.value ?? '') })
}
}
}
return list
}
const loadMediaSourceOptions = async (force = false) => {
if (!force && mediaSourceOptions.value.length > 0) {
return
}
mediaSourceLoading.value = true
try {
const res = await getSelfInputMediaSourceOptions()
mediaSourceOptions.value = normalize(res)
} catch {
mediaSourceOptions.value = []
} finally {
mediaSourceLoading.value = false
}
}
const refreshMediaSourceOptions = () => loadMediaSourceOptions(true)
return {
mediaSourceOptions,
mediaSourceLoading,
loadMediaSourceOptions,
refreshMediaSourceOptions,
}
}
@@ -0,0 +1,234 @@
<template>
<div class="edit-popup">
<popup
ref="popupRef"
:title="popupTitle"
:async="true"
width="640px"
@confirm="handleSubmit"
@close="handleClose"
>
<el-form ref="formRef" :model="formData" label-width="110px" :rules="formRules">
<el-form-item label="业绩日期" prop="yeji_date">
<el-date-picker
v-model="formData.yeji_date"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择日期"
:disabled="mode === 'edit'"
class="w-full"
/>
</el-form-item>
<el-form-item label="自媒体来源" prop="media_source">
<media-source-select
v-model="formData.media_source"
:options="mediaSourceOptions"
:loading="mediaSourceLoading"
placeholder="请选择自媒体来源"
:allow-create="false"
:disabled="mode === 'edit'"
select-class="w-full"
/>
</el-form-item>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="加粉数" prop="add_fans_count">
<el-input-number
v-model="formData.add_fans_count"
:min="0"
:step="1"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="总开口" prop="total_open_count">
<el-input-number
v-model="formData.total_open_count"
:min="0"
:step="1"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="未回复" prop="unreplied_count">
<el-input-number
v-model="formData.unreplied_count"
:min="0"
:step="1"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="付费挂号" prop="paid_appointment_count">
<el-input-number
v-model="formData.paid_appointment_count"
:min="0"
:step="1"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="免费挂号" prop="free_appointment_count">
<el-input-number
v-model="formData.free_appointment_count"
:min="0"
:step="1"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="面诊" prop="interview_count">
<el-input-number
v-model="formData.interview_count"
:min="0"
:step="1"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="订单金额" prop="order_amount">
<el-input-number
v-model="formData.order_amount"
:min="0"
:step="0.01"
:precision="2"
class="w-full"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="接诊诊单" prop="completed_order_count">
<el-input-number
v-model="formData.completed_order_count"
:min="0"
:step="1"
class="w-full"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="remark">
<el-input
v-model="formData.remark"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
maxlength="255"
show-word-limit
placeholder="选填"
/>
</el-form-item>
</el-form>
</popup>
</div>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import { personalYejiAdd, personalYejiEdit } from '@/api/self_input_stats'
import Popup from '@/components/popup/index.vue'
import MediaSourceSelect from './MediaSourceSelect.vue'
import type { MediaSourceOption } from './useMediaSourceOptions'
withDefaults(
defineProps<{
mediaSourceOptions?: MediaSourceOption[]
mediaSourceLoading?: boolean
}>(),
{
mediaSourceOptions: () => [],
mediaSourceLoading: false,
}
)
const emit = defineEmits(['success', 'close'])
const formRef = shallowRef<FormInstance>()
const popupRef = shallowRef<InstanceType<typeof Popup>>()
const mode = ref<'add' | 'edit'>('add')
const popupTitle = computed(() => (mode.value === 'edit' ? '编辑业绩' : '新增业绩'))
const formData = reactive({
id: '',
yeji_date: '',
media_source: '',
add_fans_count: 0,
total_open_count: 0,
unreplied_count: 0,
paid_appointment_count: 0,
free_appointment_count: 0,
interview_count: 0,
order_amount: 0,
completed_order_count: 0,
remark: '',
})
const formRules = {
yeji_date: [{ required: true, message: '请选择业绩日期', trigger: ['change'] }],
media_source: [{ required: true, message: '请填写自媒体来源', trigger: ['blur'] }],
add_fans_count: [{ required: true, message: '请填写加粉数', trigger: ['blur', 'change'] }],
}
const resetForm = () => {
formData.id = ''
formData.yeji_date = ''
formData.media_source = ''
formData.add_fans_count = 0
formData.total_open_count = 0
formData.unreplied_count = 0
formData.paid_appointment_count = 0
formData.free_appointment_count = 0
formData.interview_count = 0
formData.order_amount = 0
formData.completed_order_count = 0
formData.remark = ''
}
const handleSubmit = async () => {
await formRef.value?.validate()
if (mode.value === 'edit') {
await personalYejiEdit(formData)
} else {
await personalYejiAdd(formData)
}
popupRef.value?.close()
emit('success')
}
const open = (type: 'add' | 'edit' = 'add') => {
mode.value = type
resetForm()
popupRef.value?.open()
}
const setFormData = (data: Record<string, any>) => {
formData.id = data.id ?? ''
formData.yeji_date = data.yeji_date ?? ''
formData.media_source = data.media_source ?? ''
formData.add_fans_count = Number(data.add_fans_count ?? 0)
formData.total_open_count = Number(data.total_open_count ?? 0)
formData.unreplied_count = Number(data.unreplied_count ?? 0)
formData.paid_appointment_count = Number(data.paid_appointment_count ?? 0)
formData.free_appointment_count = Number(data.free_appointment_count ?? 0)
formData.interview_count = Number(data.interview_count ?? 0)
formData.order_amount = Number(data.order_amount ?? 0)
formData.completed_order_count = Number(data.completed_order_count ?? 0)
formData.remark = data.remark ?? ''
}
const handleClose = () => {
emit('close')
}
defineExpose({
open,
setFormData,
})
</script>
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace app\adminapi\controller\stats;
use app\adminapi\controller\BaseAdminController;
use app\adminapi\lists\stats\PersonalAccountCostLists;
use app\adminapi\logic\stats\PersonalAccountCostLogic;
use app\adminapi\validate\stats\PersonalAccountCostValidate;
class PersonalAccountCostController extends BaseAdminController
{
public function lists()
{
return $this->dataLists(new PersonalAccountCostLists());
}
public function add()
{
$params = (new PersonalAccountCostValidate())->post()->goCheck('add');
$result = PersonalAccountCostLogic::add($params, $this->adminId, (string) ($this->adminInfo['name'] ?? ''));
if ($result === false) {
return $this->fail(PersonalAccountCostLogic::getError());
}
return $this->success('添加成功', [], 1, 1);
}
public function edit()
{
$params = (new PersonalAccountCostValidate())->post()->goCheck('edit');
$result = PersonalAccountCostLogic::edit($params, $this->adminId, (string) ($this->adminInfo['name'] ?? ''), $this->adminInfo);
if ($result === false) {
return $this->fail(PersonalAccountCostLogic::getError());
}
return $this->success('编辑成功', [], 1, 1);
}
public function detail()
{
$params = (new PersonalAccountCostValidate())->goCheck('detail');
$detail = PersonalAccountCostLogic::detail((int) $params['id'], $this->adminId, $this->adminInfo);
if ($detail === []) {
return $this->fail('记录不存在或无权查看');
}
return $this->data($detail);
}
public function delete()
{
$params = (new PersonalAccountCostValidate())->post()->goCheck('delete');
$result = PersonalAccountCostLogic::delete((int) $params['id'], $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PersonalAccountCostLogic::getError());
}
return $this->success('删除成功', [], 1, 1);
}
}
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace app\adminapi\controller\stats;
use app\adminapi\controller\BaseAdminController;
use app\adminapi\lists\stats\PersonalYejiLists;
use app\adminapi\logic\stats\PersonalYejiLogic;
use app\adminapi\validate\stats\PersonalYejiValidate;
class PersonalYejiController extends BaseAdminController
{
public function lists()
{
return $this->dataLists(new PersonalYejiLists());
}
public function add()
{
$params = (new PersonalYejiValidate())->post()->goCheck('add');
$result = PersonalYejiLogic::add($params, $this->adminId, (string) ($this->adminInfo['name'] ?? ''));
if ($result === false) {
return $this->fail(PersonalYejiLogic::getError());
}
return $this->success('添加成功', [], 1, 1);
}
public function edit()
{
$params = (new PersonalYejiValidate())->post()->goCheck('edit');
$result = PersonalYejiLogic::edit($params, $this->adminId, (string) ($this->adminInfo['name'] ?? ''), $this->adminInfo);
if ($result === false) {
return $this->fail(PersonalYejiLogic::getError());
}
return $this->success('编辑成功', [], 1, 1);
}
public function detail()
{
$params = (new PersonalYejiValidate())->goCheck('detail');
$detail = PersonalYejiLogic::detail((int) $params['id'], $this->adminId, $this->adminInfo);
if ($detail === []) {
return $this->fail('记录不存在或无权查看');
}
return $this->data($detail);
}
public function delete()
{
$params = (new PersonalYejiValidate())->post()->goCheck('delete');
$result = PersonalYejiLogic::delete((int) $params['id'], $this->adminId, $this->adminInfo);
if ($result === false) {
return $this->fail(PersonalYejiLogic::getError());
}
return $this->success('删除成功', [], 1, 1);
}
}
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace app\adminapi\controller\stats;
use app\adminapi\controller\BaseAdminController;
use app\adminapi\logic\stats\SelfInputLogic;
class SelfInputController extends BaseAdminController
{
public function overview()
{
$result = SelfInputLogic::overview($this->request->get(), $this->adminId, $this->adminInfo);
return $this->data($result);
}
/**
* 自媒体来源下拉:从已录入业绩/账户消耗去重提取(随录入动态变化)
*/
public function mediaSourceOptions()
{
$list = SelfInputLogic::mediaSourceOptions($this->adminId, $this->adminInfo);
return $this->data($list);
}
}
@@ -132,9 +132,55 @@ class AuthMiddleware
return true;
}
// 自录转化统计:自媒体来源下拉,复用总览或账户消耗列表权限
if ($accessUri === 'stats.selfinput/mediasourceoptions') {
$selfInputAliases = [
'stats.selfinput/overview',
'stats.self_input/overview',
'stats.personalaccountcost/lists',
'stats.personal_account_cost/lists',
];
if (count(array_intersect($selfInputAliases, $AdminUris)) > 0) {
return true;
}
}
// 处方库列表:消费者开方页/处方库页导入共用,复用开方或处方库菜单权限
if ($accessUri === 'tcm.prescriptionlibrary/lists'
&& $this->matchPrescriptionLibraryListsPermission($adminUris)) {
return true;
}
return false;
}
/**
* 处方库 lists:与开方、处方库维护菜单权限互通(避免开方页「从处方库导入」403)
*/
private function matchPrescriptionLibraryListsPermission(array $adminUris): bool
{
$aliases = [
'tcm.prescriptionlibrary/lists',
'tcm.prescription/lists',
'tcm.prescription/add',
'tcm.prescription/edit',
'tcm.prescription/detail',
'cf.prescription/lists',
'cf.prescription/add',
'cf.prescription/edit',
'cf.prescription/read',
'cf.prescription/del',
'cf.prescription/audit',
'wcf.prescription/lists',
'wcf.prescription/read',
'wcf.prescription/add',
'wcf.prescription/edit',
'wcf.prescription/delete',
];
return count(array_intersect($aliases, $adminUris)) > 0;
}
/**
* 面诊进度专用:auth.admin/lists、doctor.appointment/lists + progress_board=1,不校验菜单权限
*/
@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace app\adminapi\lists\stats;
use app\adminapi\lists\BaseAdminDataLists;
use app\adminapi\logic\stats\PersonalStatsScopeTrait;
use app\common\lists\ListsExtendInterface;
use app\common\lists\ListsSearchInterface;
use app\common\lists\Traits\HasDataScopeFilter;
use app\common\model\stats\PersonalAccountCost;
class PersonalAccountCostLists extends BaseAdminDataLists implements ListsSearchInterface, ListsExtendInterface
{
use HasDataScopeFilter;
use PersonalStatsScopeTrait;
public function setSearch(): array
{
return [
'%like%' => ['media_source', 'creator_name', 'remark'],
];
}
private function baseQuery()
{
$query = PersonalAccountCost::where($this->searchWhere);
$visibleIds = $this->getDataScopeVisibleAdminIds();
$deptId = (int) ($this->params['dept_id'] ?? 0);
$finalIds = self::intersectVisibleByDept($visibleIds, $deptId);
if ($finalIds === []) {
$query->whereRaw('0 = 1');
} elseif ($finalIds !== null) {
$query->whereIn('creator_id', $finalIds);
}
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
$query->whereBetween('cost_date', [$this->params['start_date'], $this->params['end_date']]);
} elseif (!empty($this->params['start_date'])) {
$query->where('cost_date', '>=', $this->params['start_date']);
} elseif (!empty($this->params['end_date'])) {
$query->where('cost_date', '<=', $this->params['end_date']);
}
if (!empty($this->params['media_source'])) {
$query->where('media_source', trim((string) $this->params['media_source']));
}
return $query;
}
public function lists(): array
{
$rows = $this->baseQuery()
->order(['cost_date' => 'desc', 'id' => 'desc'])
->limit($this->limitOffset, $this->limitLength)
->select()
->toArray();
return self::attachDeptInfoToRows($rows);
}
public function count(): int
{
return (int) $this->baseQuery()->count();
}
public function extend(): array
{
return [
'total_amount' => round((float) $this->baseQuery()->sum('amount'), 2),
'days_count' => (int) $this->baseQuery()->distinct(true)->count('cost_date'),
];
}
}
@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace app\adminapi\lists\stats;
use app\adminapi\lists\BaseAdminDataLists;
use app\adminapi\logic\stats\PersonalStatsScopeTrait;
use app\common\lists\ListsSearchInterface;
use app\common\lists\Traits\HasDataScopeFilter;
use app\common\model\stats\PersonalYeji;
class PersonalYejiLists extends BaseAdminDataLists implements ListsSearchInterface
{
use HasDataScopeFilter;
use PersonalStatsScopeTrait;
public function setSearch(): array
{
return [
'%like%' => ['media_source', 'creator_name', 'remark'],
];
}
private function baseQuery()
{
$query = PersonalYeji::where($this->searchWhere);
$visibleIds = $this->getDataScopeVisibleAdminIds();
$deptId = (int) ($this->params['dept_id'] ?? 0);
$finalIds = self::intersectVisibleByDept($visibleIds, $deptId);
if ($finalIds === []) {
$query->whereRaw('0 = 1');
} elseif ($finalIds !== null) {
$query->whereIn('creator_id', $finalIds);
}
if (!empty($this->params['start_date']) && !empty($this->params['end_date'])) {
$query->whereBetween('yeji_date', [$this->params['start_date'], $this->params['end_date']]);
} elseif (!empty($this->params['start_date'])) {
$query->where('yeji_date', '>=', $this->params['start_date']);
} elseif (!empty($this->params['end_date'])) {
$query->where('yeji_date', '<=', $this->params['end_date']);
}
if (!empty($this->params['media_source'])) {
$query->where('media_source', trim((string) $this->params['media_source']));
}
if (!empty($this->params['creator_id'])) {
$query->where('creator_id', (int) $this->params['creator_id']);
}
return $query;
}
public function lists(): array
{
$rows = $this->baseQuery()
->order(['yeji_date' => 'desc', 'id' => 'desc'])
->limit($this->limitOffset, $this->limitLength)
->select()
->toArray();
return self::attachDeptInfoToRows($rows);
}
public function count(): int
{
return (int) $this->baseQuery()->count();
}
}
@@ -21,7 +21,7 @@ class PrescriptionLibraryLists extends BaseAdminDataLists implements ListsSearch
{
return [
'%like%' => ['prescription_name'],
'=' => ['is_public', 'creator_id']
'=' => ['is_public', 'creator_id', 'formula_type']
];
}
@@ -34,6 +34,16 @@ class PrescriptionLibraryLists extends BaseAdminDataLists implements ListsSearch
return $query;
}
// 开方页导入专用参数(勿与搜索项 creator_id 混用,否则无法 OR 出他人公开模板)
$prescribingCreatorId = (int) ($this->params['prescribing_creator_id'] ?? 0);
if ($prescribingCreatorId > 0
&& PrescriptionLibraryLogic::canListLibraryForCreator($this->adminId, $this->adminInfo, $prescribingCreatorId)) {
return $query->where(function ($q) use ($prescribingCreatorId) {
$q->where('creator_id', $prescribingCreatorId)
->whereOr('is_public', 1);
});
}
return $query->where(function ($q) {
$q->where('creator_id', $this->adminId)
->whereOr('is_public', 1);
@@ -46,7 +56,7 @@ class PrescriptionLibraryLists extends BaseAdminDataLists implements ListsSearch
public function lists(): array
{
$field = [
'id', 'prescription_name', 'herbs', 'is_public',
'id', 'prescription_name', 'formula_type', 'herbs', 'is_public',
'creator_id', 'creator_name', 'create_time', 'update_time'
];
@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
namespace app\adminapi\logic\stats;
use app\common\logic\BaseLogic;
use app\common\model\stats\PersonalAccountCost;
class PersonalAccountCostLogic extends BaseLogic
{
use PersonalStatsScopeTrait;
public static function add(array $params, int $adminId, string $adminName): bool
{
try {
$costDate = (string) $params['cost_date'];
$mediaSource = self::normalizeMediaSource((string) ($params['media_source'] ?? ''));
if ($mediaSource === '') {
self::setError('请填写自媒体来源');
return false;
}
$dupId = self::findCostDuplicateId($adminId, $costDate, $mediaSource);
if ($dupId > 0) {
self::setError("您在 {$costDate} 已录入过【{$mediaSource}】账户消耗(记录#{$dupId}),请直接编辑该记录");
return false;
}
PersonalAccountCost::create([
'cost_date' => $costDate,
'media_source' => $mediaSource,
'amount' => round((float) ($params['amount'] ?? 0), 2),
'remark' => (string) ($params['remark'] ?? ''),
'creator_id' => $adminId,
'creator_name' => $adminName,
'updater_id' => $adminId,
'updater_name' => $adminName,
'dept_id' => self::resolvePrimaryDeptId($adminId),
]);
return true;
} catch (\Throwable $e) {
if (self::isUniqueConstraintViolation($e)) {
self::setError('该日期下该渠道的账户消耗已存在(唯一索引冲突),请刷新列表后直接编辑');
} else {
self::setError($e->getMessage());
}
return false;
}
}
public static function edit(array $params, int $adminId, string $adminName, array $adminInfo): bool
{
try {
$model = PersonalAccountCost::find($params['id']);
if (!$model) {
self::setError('记录不存在');
return false;
}
if (!self::assertRecordVisible($adminId, $adminInfo, (int) $model->creator_id)) {
self::setError('无权操作该记录');
return false;
}
$model->amount = round((float) ($params['amount'] ?? 0), 2);
$model->remark = (string) ($params['remark'] ?? '');
$model->updater_id = $adminId;
$model->updater_name = $adminName;
$model->save();
return true;
} catch (\Throwable $e) {
self::setError($e->getMessage());
return false;
}
}
public static function delete(int $id, int $adminId, array $adminInfo): bool
{
try {
$model = PersonalAccountCost::find($id);
if (!$model) {
self::setError('记录不存在');
return false;
}
if (!self::assertRecordVisible($adminId, $adminInfo, (int) $model->creator_id)) {
self::setError('无权操作该记录');
return false;
}
$model->delete();
return true;
} catch (\Throwable $e) {
self::setError($e->getMessage());
return false;
}
}
public static function detail(int $id, int $adminId, array $adminInfo): array
{
$model = PersonalAccountCost::find($id);
if (!$model) {
return [];
}
if (!self::assertRecordVisible($adminId, $adminInfo, (int) $model->creator_id)) {
return [];
}
return $model->toArray();
}
}
@@ -0,0 +1,252 @@
<?php
declare(strict_types=1);
namespace app\adminapi\logic\stats;
use app\adminapi\logic\dept\DeptLogic;
use app\common\model\auth\AdminDept;
use app\common\model\dept\Dept;
use app\common\model\stats\PersonalAccountCost;
use app\common\model\stats\PersonalYeji;
use app\common\service\DataScope\DataScopeService;
use think\facade\Config;
trait PersonalStatsScopeTrait
{
protected static function resolvePrimaryDeptId(int $adminId): int
{
if ($adminId <= 0) {
return 0;
}
$deptId = AdminDept::where('admin_id', $adminId)->value('dept_id');
return (int) ($deptId ?: 0);
}
/**
* @param array<int, int> $creatorIds
* @return array{0: array<int, int>, 1: array<int, string>, 2: array<int, string>}
* [adminId => deptId, deptId => name, deptId => "祖/父/当前"]
*/
protected static function loadAdminDeptMap(array $creatorIds): array
{
$creatorIds = array_values(array_unique(array_filter(array_map('intval', $creatorIds))));
if ($creatorIds === []) {
return [[], [], []];
}
$rows = AdminDept::whereIn('admin_id', $creatorIds)
->field('admin_id, dept_id')
->select()
->toArray();
$adminToDeptId = [];
foreach ($rows as $row) {
$adminId = (int) ($row['admin_id'] ?? 0);
$deptId = (int) ($row['dept_id'] ?? 0);
if ($adminId <= 0 || $deptId <= 0) {
continue;
}
if (!isset($adminToDeptId[$adminId])) {
$adminToDeptId[$adminId] = $deptId;
}
}
if ($adminToDeptId === []) {
return [[], [], []];
}
$allDeptRows = Dept::field('id, pid, name')->select()->toArray();
$deptIndex = [];
foreach ($allDeptRows as $row) {
$id = (int) ($row['id'] ?? 0);
if ($id <= 0) {
continue;
}
$deptIndex[$id] = [
'pid' => (int) ($row['pid'] ?? 0),
'name' => (string) ($row['name'] ?? ''),
];
}
$deptNameMap = [];
$deptPathMap = [];
foreach (array_unique(array_values($adminToDeptId)) as $deptId) {
$deptId = (int) $deptId;
if ($deptId <= 0 || !isset($deptIndex[$deptId])) {
continue;
}
$deptNameMap[$deptId] = $deptIndex[$deptId]['name'];
$deptPathMap[$deptId] = self::resolveDeptPath($deptId, $deptIndex);
}
return [$adminToDeptId, $deptNameMap, $deptPathMap];
}
/**
* 从根节点到当前部门的完整链路(用 / 分隔)。
*
* @param array<int, array{pid: int, name: string}> $deptIndex
*/
private static function resolveDeptPath(int $deptId, array $deptIndex): string
{
$names = [];
$guard = 0;
$cursor = $deptId;
while ($cursor > 0 && isset($deptIndex[$cursor]) && $guard++ < 32) {
$node = $deptIndex[$cursor];
$name = trim($node['name']);
if ($name !== '') {
array_unshift($names, $name);
}
$cursor = $node['pid'];
}
return implode(' / ', $names);
}
/**
* @param array<int, array<string, mixed>> $rows
* @return array<int, array<string, mixed>>
*/
protected static function attachDeptInfoToRows(array $rows): array
{
if ($rows === []) {
return $rows;
}
$creatorIds = array_map(static fn (array $row): int => (int) ($row['creator_id'] ?? 0), $rows);
[$adminToDeptId, $deptNameMap, $deptPathMap] = self::loadAdminDeptMap($creatorIds);
foreach ($rows as &$row) {
$creatorId = (int) ($row['creator_id'] ?? 0);
$deptId = $adminToDeptId[$creatorId] ?? 0;
$row['dept_id'] = $deptId;
$row['dept_name'] = $deptId > 0 ? (string) ($deptNameMap[$deptId] ?? '') : '';
$row['dept_path'] = $deptId > 0 ? (string) ($deptPathMap[$deptId] ?? '') : '';
}
unset($row);
return $rows;
}
/**
* 根据 dept_id(包含其子部门)收窄可见 admin id 集合。
* 与 visibleAdminIds 取交集。
*
* @param array<int>|null $visibleAdminIds null 表示不限
* @return array<int>|null 返回 null 表示外部条件无需附加;返回 [] 表示无可见 admin
*/
protected static function intersectVisibleByDept(?array $visibleAdminIds, int $deptId): ?array
{
if ($deptId <= 0) {
return $visibleAdminIds;
}
$deptIds = DeptLogic::getSelfAndDescendantIds($deptId);
if ($deptIds === []) {
$deptIds = [$deptId];
}
$adminIds = AdminDept::whereIn('dept_id', $deptIds)->column('admin_id');
$adminIds = array_values(array_unique(array_filter(array_map('intval', $adminIds), static fn (int $v): bool => $v > 0)));
if ($visibleAdminIds === null) {
return $adminIds;
}
return array_values(array_intersect($visibleAdminIds, $adminIds));
}
protected static function normalizeMediaSource(string $mediaSource): string
{
return trim($mediaSource);
}
/**
* 与 project.self_input_stats_view_all_roles 一致:超管或白名单角色可见全部录入人数据。
*/
protected static function canViewAllSelfInputStats(array $adminInfo): bool
{
if ((int) ($adminInfo['root'] ?? 0) === 1) {
return true;
}
$allow = Config::get('project.self_input_stats_view_all_roles', []);
$allow = array_map('intval', is_array($allow) ? $allow : []);
if ($allow === []) {
return false;
}
$myRoles = array_map('intval', $adminInfo['role_id'] ?? []);
return count(array_intersect($myRoles, $allow)) > 0;
}
/**
* @return array<int>|null null=全部录入人;[]=无可见;int[]=可见 creator_id 集合
*/
protected static function getVisibleCreatorIds(int $adminId, array $adminInfo): ?array
{
if (self::canViewAllSelfInputStats($adminInfo)) {
return null;
}
return DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
}
protected static function assertRecordVisible(int $adminId, array $adminInfo, int $creatorId): bool
{
$visibleIds = self::getVisibleCreatorIds($adminId, $adminInfo);
if ($visibleIds === null) {
return true;
}
return in_array($creatorId, $visibleIds, true);
}
/**
* 同一录入人 + 同一天 + 同一渠道唯一(不同录入人可同日同渠道各录一条)。
* 命中返回冲突记录 ID,未命中返回 0。
*/
protected static function findYejiDuplicateId(int $creatorId, string $yejiDate, string $mediaSource, int $excludeId = 0): int
{
$query = PersonalYeji::where('creator_id', $creatorId)
->where('yeji_date', $yejiDate)
->where('media_source', $mediaSource)
->whereNull('delete_time');
if ($excludeId > 0) {
$query->where('id', '<>', $excludeId);
}
return (int) ($query->value('id') ?? 0);
}
protected static function isYejiDuplicate(int $creatorId, string $yejiDate, string $mediaSource, int $excludeId = 0): bool
{
return self::findYejiDuplicateId($creatorId, $yejiDate, $mediaSource, $excludeId) > 0;
}
/**
* 同一录入人 + 同一天 + 同一渠道唯一(不同录入人可同日同渠道各录一条)。
*/
protected static function findCostDuplicateId(int $creatorId, string $costDate, string $mediaSource, int $excludeId = 0): int
{
$query = PersonalAccountCost::where('creator_id', $creatorId)
->where('cost_date', $costDate)
->where('media_source', $mediaSource)
->whereNull('delete_time');
if ($excludeId > 0) {
$query->where('id', '<>', $excludeId);
}
return (int) ($query->value('id') ?? 0);
}
protected static function isCostDuplicate(int $creatorId, string $costDate, string $mediaSource, int $excludeId = 0): bool
{
return self::findCostDuplicateId($creatorId, $costDate, $mediaSource, $excludeId) > 0;
}
/**
* MySQL 唯一索引冲突 1062 兜底转友好提示(避免裸 SQL 异常)。
*/
protected static function isUniqueConstraintViolation(\Throwable $e): bool
{
return (int) $e->getCode() === 23000 || str_contains($e->getMessage(), '1062');
}
}
@@ -0,0 +1,139 @@
<?php
declare(strict_types=1);
namespace app\adminapi\logic\stats;
use app\common\logic\BaseLogic;
use app\common\model\stats\PersonalYeji;
class PersonalYejiLogic extends BaseLogic
{
use PersonalStatsScopeTrait;
public static function add(array $params, int $adminId, string $adminName): bool
{
try {
$yejiDate = (string) $params['yeji_date'];
$mediaSource = self::normalizeMediaSource((string) ($params['media_source'] ?? ''));
if ($mediaSource === '') {
self::setError('请填写自媒体来源');
return false;
}
$dupId = self::findYejiDuplicateId($adminId, $yejiDate, $mediaSource);
if ($dupId > 0) {
self::setError("您在 {$yejiDate} 已录入过【{$mediaSource}】业绩(记录#{$dupId}),请直接编辑该记录");
return false;
}
PersonalYeji::create([
'yeji_date' => $yejiDate,
'media_source' => $mediaSource,
'add_fans_count' => (int) ($params['add_fans_count'] ?? 0),
'total_open_count' => (int) ($params['total_open_count'] ?? 0),
'unreplied_count' => (int) ($params['unreplied_count'] ?? 0),
'paid_appointment_count' => (int) ($params['paid_appointment_count'] ?? 0),
'free_appointment_count' => (int) ($params['free_appointment_count'] ?? 0),
'interview_count' => (int) ($params['interview_count'] ?? 0),
'order_amount' => round((float) ($params['order_amount'] ?? 0), 2),
'completed_order_count' => (int) ($params['completed_order_count'] ?? 0),
'remark' => (string) ($params['remark'] ?? ''),
'creator_id' => $adminId,
'creator_name' => $adminName,
'updater_id' => $adminId,
'updater_name' => $adminName,
'dept_id' => self::resolvePrimaryDeptId($adminId),
]);
return true;
} catch (\Throwable $e) {
if (self::isUniqueConstraintViolation($e)) {
self::setError('该日期下该渠道的业绩已存在(唯一索引冲突),请刷新列表后直接编辑');
} else {
self::setError($e->getMessage());
}
return false;
}
}
public static function edit(array $params, int $adminId, string $adminName, array $adminInfo): bool
{
try {
$model = PersonalYeji::find($params['id']);
if (!$model) {
self::setError('记录不存在');
return false;
}
if (!self::assertRecordVisible($adminId, $adminInfo, (int) $model->creator_id)) {
self::setError('无权操作该记录');
return false;
}
$model->add_fans_count = (int) ($params['add_fans_count'] ?? 0);
$model->total_open_count = (int) ($params['total_open_count'] ?? 0);
$model->unreplied_count = (int) ($params['unreplied_count'] ?? 0);
$model->paid_appointment_count = (int) ($params['paid_appointment_count'] ?? 0);
$model->free_appointment_count = (int) ($params['free_appointment_count'] ?? 0);
$model->interview_count = (int) ($params['interview_count'] ?? 0);
$model->order_amount = round((float) ($params['order_amount'] ?? 0), 2);
$model->completed_order_count = (int) ($params['completed_order_count'] ?? 0);
$model->remark = (string) ($params['remark'] ?? '');
$model->updater_id = $adminId;
$model->updater_name = $adminName;
$model->save();
return true;
} catch (\Throwable $e) {
self::setError($e->getMessage());
return false;
}
}
public static function delete(int $id, int $adminId, array $adminInfo): bool
{
try {
$model = PersonalYeji::find($id);
if (!$model) {
self::setError('记录不存在');
return false;
}
if (!self::assertRecordVisible($adminId, $adminInfo, (int) $model->creator_id)) {
self::setError('无权操作该记录');
return false;
}
$model->delete();
return true;
} catch (\Throwable $e) {
self::setError($e->getMessage());
return false;
}
}
public static function detail(int $id, int $adminId, array $adminInfo): array
{
$model = PersonalYeji::find($id);
if (!$model) {
return [];
}
if (!self::assertRecordVisible($adminId, $adminInfo, (int) $model->creator_id)) {
return [];
}
return $model->toArray();
}
}
@@ -0,0 +1,384 @@
<?php
declare(strict_types=1);
namespace app\adminapi\logic\stats;
use app\common\logic\BaseLogic;
use app\common\model\dict\DictData;
use app\common\model\stats\PersonalAccountCost;
use app\common\model\stats\PersonalYeji;
class SelfInputLogic extends BaseLogic
{
use PersonalStatsScopeTrait;
public static function overview(array $params, int $adminId, array $adminInfo): array
{
[$startDate, $endDate] = self::resolveTimeRange($params);
$pageNo = max(1, (int) ($params['page_no'] ?? 1));
$pageSize = min(100, max(1, (int) ($params['page_size'] ?? 15)));
$mediaSource = trim((string) ($params['media_source'] ?? ''));
$deptId = (int) ($params['dept_id'] ?? 0);
$effectiveAdminIds = self::resolveEffectiveAdminIds($adminId, $adminInfo, $deptId);
$yejiQuery = self::buildYejiQuery($startDate, $endDate, $effectiveAdminIds);
if ($mediaSource !== '') {
$yejiQuery->where('media_source', $mediaSource);
}
$count = (int) (clone $yejiQuery)->count();
$rows = (clone $yejiQuery)
->order(['yeji_date' => 'desc', 'id' => 'desc'])
->page($pageNo, $pageSize)
->select()
->toArray();
$costMap = self::loadAccountCostMap($startDate, $endDate, $effectiveAdminIds, $mediaSource);
$lists = [];
foreach ($rows as $row) {
$entity = self::normalizeYejiRow($row);
$costKey = self::buildCostKey(
(int) $entity['creator_id'],
(string) $entity['yeji_date'],
(string) $entity['media_source']
);
$entity['account_cost'] = round((float) ($costMap[$costKey] ?? 0), 2);
$lists[] = self::finalizeMetrics($entity);
}
$lists = self::attachDeptInfoToRows($lists);
$allYejiRows = self::buildYejiQuery($startDate, $endDate, $effectiveAdminIds);
if ($mediaSource !== '') {
$allYejiRows->where('media_source', $mediaSource);
}
$allYeji = $allYejiRows->select()->toArray();
$summaryCostMap = $costMap;
$summaryBase = self::emptyMetrics();
foreach ($allYeji as $row) {
$entity = self::normalizeYejiRow($row);
$costKey = self::buildCostKey(
(int) $entity['creator_id'],
(string) $entity['yeji_date'],
(string) $entity['media_source']
);
$entity['account_cost'] = round((float) ($summaryCostMap[$costKey] ?? 0), 2);
unset($summaryCostMap[$costKey]);
$entity = self::finalizeMetrics($entity);
$summaryBase = self::accumulateMetrics($summaryBase, $entity);
}
foreach ($summaryCostMap as $amount) {
$summaryBase['account_cost'] += round((float) $amount, 2);
}
$summary = self::finalizeMetrics($summaryBase);
$canViewFinance = self::canViewAllSelfInputStats($adminInfo);
if (!$canViewFinance) {
$summary = self::maskFinanceFields($summary);
foreach ($lists as &$item) {
$item = self::maskFinanceFields($item);
}
unset($item);
}
return [
'summary' => $summary,
'lists' => $lists,
'count' => $count,
'page_no' => $pageNo,
'page_size' => $pageSize,
'extend' => [
'summary' => $summary,
'date_range' => [$startDate, $endDate],
'can_view_finance' => $canViewFinance,
],
];
}
/**
* 财务相关字段(账户消耗 / 现金成本 / ROI):非豁免角色不可见,剔除字段避免被嗅探。
*
* @param array<string, mixed> $entity
* @return array<string, mixed>
*/
private static function maskFinanceFields(array $entity): array
{
foreach (['account_cost', 'cash_cost', 'roi'] as $key) {
unset($entity[$key]);
}
return $entity;
}
/**
* 自媒体来源选项:来自字典「推广渠道」(type_value=channels),按 sort/id 排序。
* 用 dict_data.name 作为存储值(与历史录入兼容;保留 value 仅作展示标识)。
*
* @return array<int, array{name: string, value: string}>
*/
public static function mediaSourceOptions(int $adminId, array $adminInfo): array
{
unset($adminId, $adminInfo);
$rows = DictData::where('type_value', 'channels')
->where('status', 1)
->order(['sort' => 'desc', 'id' => 'asc'])
->field('name, value')
->select()
->toArray();
$list = [];
$seen = [];
foreach ($rows as $row) {
$name = self::normalizeMediaSource((string) ($row['name'] ?? ''));
if ($name === '' || isset($seen[$name])) {
continue;
}
$seen[$name] = true;
$list[] = [
'name' => $name,
'value' => (string) ($row['value'] ?? ''),
];
}
return $list;
}
/**
* @return array<int>|null null = 不限;[] = 无可见
*/
private static function resolveEffectiveAdminIds(int $adminId, array $adminInfo, int $deptId): ?array
{
$visibleIds = self::getVisibleCreatorIds($adminId, $adminInfo);
return self::intersectVisibleByDept($visibleIds, $deptId);
}
/**
* @param array<int>|null $effectiveAdminIds
*/
private static function buildYejiQuery(string $startDate, string $endDate, ?array $effectiveAdminIds)
{
$query = PersonalYeji::whereBetween('yeji_date', [$startDate, $endDate]);
if ($effectiveAdminIds === []) {
$query->whereRaw('0 = 1');
} elseif ($effectiveAdminIds !== null) {
$query->whereIn('creator_id', $effectiveAdminIds);
}
return $query;
}
/**
* @param array<int>|null $effectiveAdminIds
* @return array<string, float>
*/
private static function loadAccountCostMap(
string $startDate,
string $endDate,
?array $effectiveAdminIds,
string $mediaSource
): array {
$query = PersonalAccountCost::whereBetween('cost_date', [$startDate, $endDate]);
if ($effectiveAdminIds === []) {
return [];
}
if ($effectiveAdminIds !== null) {
$query->whereIn('creator_id', $effectiveAdminIds);
}
if ($mediaSource !== '') {
$query->where('media_source', $mediaSource);
}
$rows = $query
->fieldRaw('creator_id, cost_date, media_source, SUM(amount) AS total_amount')
->group('creator_id, cost_date, media_source')
->select()
->toArray();
$map = [];
foreach ($rows as $row) {
$key = self::buildCostKey(
(int) $row['creator_id'],
(string) $row['cost_date'],
(string) $row['media_source']
);
$map[$key] = round((float) ($row['total_amount'] ?? 0), 2);
}
return $map;
}
private static function buildCostKey(int $creatorId, string $date, string $mediaSource): string
{
return $creatorId . '|' . $date . '|' . self::normalizeMediaSource($mediaSource);
}
/**
* @param array<string, mixed> $row
* @return array<string, mixed>
*/
private static function normalizeYejiRow(array $row): array
{
return [
'id' => (int) ($row['id'] ?? 0),
'yeji_date' => (string) ($row['yeji_date'] ?? ''),
'media_source' => (string) ($row['media_source'] ?? ''),
'creator_id' => (int) ($row['creator_id'] ?? 0),
'creator_name' => (string) ($row['creator_name'] ?? ''),
'remark' => (string) ($row['remark'] ?? ''),
'add_fans_count' => (int) ($row['add_fans_count'] ?? 0),
'total_open_count' => (int) ($row['total_open_count'] ?? 0),
'unreplied_count' => (int) ($row['unreplied_count'] ?? 0),
'paid_appointment_count' => (int) ($row['paid_appointment_count'] ?? 0),
'free_appointment_count' => (int) ($row['free_appointment_count'] ?? 0),
'interview_count' => (int) ($row['interview_count'] ?? 0),
'order_amount' => round((float) ($row['order_amount'] ?? 0), 2),
'completed_order_count' => (int) ($row['completed_order_count'] ?? 0),
'account_cost' => 0.0,
];
}
/**
* @return array<string, mixed>
*/
private static function emptyMetrics(): array
{
return [
'add_fans_count' => 0,
'total_open_count' => 0,
'unreplied_count' => 0,
'paid_appointment_count' => 0,
'free_appointment_count' => 0,
'appointment_total_count' => 0,
'interview_count' => 0,
'order_amount' => 0.0,
'completed_order_count' => 0,
'account_cost' => 0.0,
];
}
/**
* @param array<string, mixed> $base
* @param array<string, mixed> $row
* @return array<string, mixed>
*/
private static function accumulateMetrics(array $base, array $row): array
{
$base['add_fans_count'] += (int) ($row['add_fans_count'] ?? 0);
$base['total_open_count'] += (int) ($row['total_open_count'] ?? 0);
$base['unreplied_count'] += (int) ($row['unreplied_count'] ?? 0);
$base['paid_appointment_count'] += (int) ($row['paid_appointment_count'] ?? 0);
$base['free_appointment_count'] += (int) ($row['free_appointment_count'] ?? 0);
$base['interview_count'] += (int) ($row['interview_count'] ?? 0);
$base['order_amount'] = round((float) $base['order_amount'] + (float) ($row['order_amount'] ?? 0), 2);
$base['completed_order_count'] += (int) ($row['completed_order_count'] ?? 0);
$base['account_cost'] = round((float) $base['account_cost'] + (float) ($row['account_cost'] ?? 0), 2);
return $base;
}
/**
* @param array<string, mixed> $entity
* @return array<string, mixed>
*/
private static function finalizeMetrics(array $entity): array
{
$paidAppointmentCount = (int) ($entity['paid_appointment_count'] ?? 0);
$freeAppointmentCount = (int) ($entity['free_appointment_count'] ?? 0);
$appointmentTotalCount = $paidAppointmentCount + $freeAppointmentCount;
$interviewCount = (int) ($entity['interview_count'] ?? 0);
$addFansCount = (int) ($entity['add_fans_count'] ?? 0);
$totalOpenCount = (int) ($entity['total_open_count'] ?? 0);
$completedOrderCount = (int) ($entity['completed_order_count'] ?? 0);
$orderAmount = round((float) ($entity['order_amount'] ?? 0), 2);
$accountCost = round((float) ($entity['account_cost'] ?? 0), 2);
$entity['appointment_total_count'] = $appointmentTotalCount;
$entity['order_amount'] = $orderAmount;
$entity['account_cost'] = $accountCost;
$entity['paid_appointment_rate'] = self::percent($paidAppointmentCount, $addFansCount);
$entity['open_appointment_rate'] = self::percent($paidAppointmentCount, $totalOpenCount);
$entity['interview_rate'] = self::percent($interviewCount, $appointmentTotalCount);
$entity['receive_rate'] = self::percent($completedOrderCount, $addFansCount);
$entity['interview_receive_rate'] = self::percent($completedOrderCount, $interviewCount);
$entity['open_receive_rate'] = self::percent($completedOrderCount, $totalOpenCount);
$entity['avg_unit_price'] = self::safeDivideMoney($orderAmount, $completedOrderCount);
$entity['cash_cost'] = self::safeDivideMoney($accountCost, $addFansCount);
$entity['roi'] = self::safeDivideRatio($orderAmount, $accountCost);
return $entity;
}
/**
* @return array{0: string, 1: string}
*/
private static function resolveTimeRange(array $params): array
{
$today = date('Y-m-d');
$timeType = (string) ($params['time_type'] ?? 'today');
switch ($timeType) {
case 'yesterday':
$startDate = date('Y-m-d', strtotime('-1 day'));
$endDate = $startDate;
break;
case 'week':
$startDate = date('Y-m-d', strtotime('-6 days'));
$endDate = $today;
break;
case 'month':
$startDate = date('Y-m-d', strtotime('-29 days'));
$endDate = $today;
break;
case 'custom':
$startDate = trim((string) ($params['start_date'] ?? ''));
$endDate = trim((string) ($params['end_date'] ?? ''));
if ($startDate === '' || $endDate === '') {
$startDate = $today;
$endDate = $today;
} elseif ($startDate > $endDate) {
[$startDate, $endDate] = [$endDate, $startDate];
}
break;
case 'today':
default:
$startDate = $today;
$endDate = $today;
}
return [$startDate, $endDate];
}
private static function percent(int $numerator, int $denominator): float
{
if ($denominator <= 0) {
return 0.0;
}
return round(($numerator / $denominator) * 100, 2);
}
private static function safeDivideMoney(float $numerator, int $denominator): float
{
if ($denominator <= 0) {
return 0.0;
}
return round($numerator / $denominator, 2);
}
private static function safeDivideRatio(float $numerator, float $denominator): float
{
if ($denominator <= 0) {
return 0.0;
}
return round($numerator / $denominator, 2);
}
}
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace app\adminapi\logic\tcm;
use app\common\cache\AdminAuthCache;
use app\common\logic\BaseLogic;
use app\common\model\auth\AdminRole;
use app\common\model\tcm\PrescriptionLibrary;
@@ -33,12 +34,64 @@ class PrescriptionLibraryLogic extends BaseLogic
return count(array_intersect($myRoles, $allowRoles)) > 0;
}
/**
* @notes 是否具备消费者/诊间开方相关菜单权限(用于处方库列表鉴权别名)
*/
public static function hasPrescriptionOperatePermission(int $adminId): bool
{
$cache = new AdminAuthCache($adminId);
$uris = $cache->getAdminUri() ?? [];
$normalized = array_map(static fn ($item) => strtolower((string) $item), $uris);
$allowed = [
'tcm.prescription/lists',
'tcm.prescription/add',
'tcm.prescription/edit',
'tcm.prescription/detail',
'cf.prescription/lists',
'cf.prescription/add',
'cf.prescription/edit',
'cf.prescription/read',
'cf.prescription/del',
'cf.prescription/audit',
'wcf.prescription/lists',
'wcf.prescription/read',
'wcf.prescription/add',
'wcf.prescription/edit',
'wcf.prescription/delete',
'tcm.prescriptionlibrary/lists',
];
return count(array_intersect($allowed, $normalized)) > 0;
}
/**
* @notes 开方页按医师 creator_id 拉取处方库:本人 / 超管角色 / 有开方菜单权限(医助代开方)
*/
public static function canListLibraryForCreator(int $adminId, array $adminInfo, int $targetCreatorId): bool
{
if ($targetCreatorId <= 0) {
return false;
}
if ($targetCreatorId === $adminId) {
return true;
}
if (self::canManageAllPrescriptions($adminId, $adminInfo)) {
return true;
}
return self::hasPrescriptionOperatePermission($adminId);
}
/**
* @notes 添加处方库
*/
public static function add(array $params): ?int
{
try {
$params['formula_type'] = in_array($params['formula_type'] ?? '', ['主方', '辅方'], true)
? $params['formula_type']
: '主方';
// 处理药材数据
if (isset($params['herbs']) && is_array($params['herbs'])) {
$params['herbs'] = json_encode($params['herbs'], JSON_UNESCAPED_UNICODE);
@@ -69,6 +122,12 @@ class PrescriptionLibraryLogic extends BaseLogic
return false;
}
if (isset($params['formula_type'])) {
$params['formula_type'] = in_array($params['formula_type'], ['主方', '辅方'], true)
? $params['formula_type']
: '主方';
}
// 处理药材数据
if (isset($params['herbs']) && is_array($params['herbs'])) {
$params['herbs'] = json_encode($params['herbs'], JSON_UNESCAPED_UNICODE);
@@ -159,6 +159,35 @@ class PrescriptionLogic
return $ts ? date('Y-m-d', $ts) : date('Y-m-d');
}
/**
* @notes 辅方用法 JSON(与主方 dosage/times/days 字段结构一致)
*/
private static function normalizeAuxUsage(array $params): ?array
{
$raw = $params['aux_usage'] ?? null;
if ($raw === null || $raw === '' || $raw === []) {
return null;
}
if (is_string($raw)) {
$decoded = json_decode($raw, true);
$raw = is_array($decoded) ? $decoded : null;
}
if (!is_array($raw)) {
return null;
}
return [
'dosage_amount' => isset($raw['dosage_amount']) && $raw['dosage_amount'] !== ''
? (float) $raw['dosage_amount']
: null,
'dosage_bag_count' => self::normalizeDosageBagCount($raw['dosage_bag_count'] ?? 1),
'need_decoction' => (int) ($raw['need_decoction'] ?? 0),
'bags_per_dose' => isset($raw['bags_per_dose']) ? (int) $raw['bags_per_dose'] : 1,
'times_per_day' => (int) ($raw['times_per_day'] ?? 3),
'usage_days' => (int) ($raw['usage_days'] ?? 7),
];
}
private static function normalizeDosageBagCount($raw): int
{
$count = (int) $raw;
@@ -273,6 +302,7 @@ class PrescriptionLogic
'dose_unit' => $params['dose_unit'] ?? '剂',
'usage_days' => (int)($params['usage_days'] ?? 7),
'times_per_day' => (int)($params['times_per_day'] ?? 2),
'aux_usage' => self::normalizeAuxUsage($params),
'usage_instruction' => $params['usage_instruction'] ?? '水煎服一日二次',
'usage_time' => $params['usage_time'] ?? '饭前',
'usage_way' => $params['usage_way'] ?? '温水送服',
@@ -398,6 +428,9 @@ class PrescriptionLogic
'dose_unit' => $params['dose_unit'] ?? $prescription->dose_unit,
'usage_days' => (int)($params['usage_days'] ?? $prescription->usage_days),
'times_per_day' => (int)($params['times_per_day'] ?? $prescription->times_per_day ?? 2),
'aux_usage' => array_key_exists('aux_usage', $params)
? self::normalizeAuxUsage($params)
: $prescription->aux_usage,
'usage_instruction' => $params['usage_instruction'] ?? $prescription->usage_instruction,
'usage_time' => $params['usage_time'] ?? $prescription->usage_time,
'usage_way' => $params['usage_way'] ?? $prescription->usage_way,
@@ -930,6 +963,8 @@ class PrescriptionLogic
$visitNo = '1K' . str_pad((string) $diagnosisId, 8, '0', STR_PAD_LEFT);
$herbs = [];
// 与手动开方一致:保存诊单详情快照,供病历打印/查看
$caseRecord = DiagnosisLogic::detail(['id' => $diagnosisId]);
$data = [
'sn' => $sn,
@@ -954,7 +989,7 @@ class PrescriptionLogic
'tongue' => (string) ($diagnosis->tongue ?? ''),
'tongue_image' => '',
'clinical_diagnosis' => $clinical,
'case_record' => [],
'case_record' => $caseRecord ?: [],
'herbs' => $herbs,
'dose_count' => 1,
'dose_unit' => '剂',
@@ -156,6 +156,24 @@ class PrescriptionOrderLogic
return in_array((int) $row->creator_id, $ids, true);
}
/**
* 是否已分配「处方业务订单」相关菜单/按钮权限(lists、detail、审核等任一子权限即可)
*/
public static function hasPrescriptionOrderMenuAccess(array $adminInfo): bool
{
if (!empty($adminInfo['root']) && (int) $adminInfo['root'] === 1) {
return true;
}
$perms = AuthLogic::getAuthByAdminId((int) ($adminInfo['admin_id'] ?? 0));
foreach ($perms as $p) {
if (is_string($p) && str_starts_with($p, 'tcm.prescriptionOrder/')) {
return true;
}
}
return false;
}
/**
* @param PrescriptionOrder $row
*/
@@ -164,6 +182,9 @@ class PrescriptionOrderLogic
if (self::canSeeAllPrescriptionOrders($adminInfo)) {
return true;
}
if (self::hasPrescriptionOrderMenuAccess($adminInfo)) {
return true;
}
if ((int) $row->creator_id === $adminId) {
return true;
}
@@ -1366,6 +1387,7 @@ class PrescriptionOrderLogic
$payload['official_urls'] = ExpressTrackService::officialUrls($num);
$payload['tracking_number'] = $num;
$payload['order_id'] = $id;
$payload['express_company_used'] = $ec;
return $payload;
@@ -2519,7 +2541,7 @@ class PrescriptionOrderLogic
}
/**
* 导出用:诊单医助在 admin_dept 中的部门路径(多部门「;」、路径内「 / 」)
* 导出用:管理员在 admin_dept 中的部门路径(多部门「;」、路径内「 / 」;业务订单导出取 creator_id
*/
public static function formatAssistantDeptPathForExport(int $assistantAdminId): string
{
@@ -2809,21 +2831,21 @@ class PrescriptionOrderLogic
$item['export_patient_gender'] = $g === 1 ? '男' : '女';
$item['export_patient_age'] = (string) ($dg['age'] ?? '');
$item['export_patient_phone'] = (string) ($dg['phone'] ?? '');
$rxAst = \is_array($rx) ? (int) ($rx['assistant_id'] ?? 0) : 0;
$diagAst = (int) ($dg['assistant_id'] ?? 0);
$astId = self::resolveAssistantAdminIdForPrescriptionOrderRow($rxAst, $diagAst);
if ($astId > 0) {
if (!isset($assistantDeptCache[$astId])) {
$assistantDeptCache[$astId] = self::formatAssistantDeptPathForExport($astId);
}
$item['export_assistant_dept'] = $assistantDeptCache[$astId];
} else {
$item['export_assistant_dept'] = '';
}
} else {
$item['export_patient_gender'] = '';
$item['export_patient_age'] = '';
$item['export_patient_phone'] = '';
}
// 导出「医助名字 / 医助部门」:与详情 order_creator 一致,按业务订单 creator_id(非诊单二诊 assistant_id
$creatorId = (int) ($item['creator_id'] ?? 0);
$item['assistant_name'] = (string) ($item['creator_name'] ?? '');
if ($creatorId > 0) {
if (!isset($assistantDeptCache[$creatorId])) {
$assistantDeptCache[$creatorId] = self::formatAssistantDeptPathForExport($creatorId);
}
$item['export_assistant_dept'] = $assistantDeptCache[$creatorId];
} else {
$item['export_assistant_dept'] = '';
}
@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace app\adminapi\validate\stats;
use app\common\model\stats\PersonalAccountCost;
use app\common\validate\BaseValidate;
class PersonalAccountCostValidate extends BaseValidate
{
protected $rule = [
'id' => 'require|checkExists',
'cost_date' => 'require|dateFormat:Y-m-d',
'media_source' => 'require|max:120',
'amount' => 'require|float|egt:0',
'remark' => 'max:255',
];
protected $message = [
'id.require' => '参数缺失',
'cost_date.require' => '请选择日期',
'cost_date.dateFormat' => '日期格式错误',
'media_source.require' => '请填写自媒体来源',
'media_source.max' => '自媒体来源不能超过120个字符',
'amount.require' => '请输入账户消耗金额',
'amount.float' => '账户消耗金额格式错误',
'amount.egt' => '账户消耗金额不能小于0',
'remark.max' => '备注不能超过255个字符',
];
public function sceneAdd()
{
return $this->remove('id', true);
}
public function sceneEdit()
{
return $this->remove('cost_date', true)->remove('media_source', true);
}
public function sceneDetail()
{
return $this->only(['id']);
}
public function sceneDelete()
{
return $this->only(['id']);
}
public function checkExists($value)
{
$model = PersonalAccountCost::find($value);
if (!$model) {
return '记录不存在';
}
return true;
}
}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace app\adminapi\validate\stats;
use app\common\model\stats\PersonalYeji;
use app\common\validate\BaseValidate;
class PersonalYejiValidate extends BaseValidate
{
protected $rule = [
'id' => 'require|checkExists',
'yeji_date' => 'require|dateFormat:Y-m-d',
'media_source' => 'require|max:120',
'add_fans_count' => 'require|integer|egt:0',
'total_open_count' => 'integer|egt:0',
'unreplied_count' => 'integer|egt:0',
'paid_appointment_count' => 'integer|egt:0',
'free_appointment_count' => 'integer|egt:0',
'interview_count' => 'integer|egt:0',
'order_amount' => 'float|egt:0',
'completed_order_count' => 'integer|egt:0',
'remark' => 'max:255',
];
protected $message = [
'id.require' => '参数缺失',
'yeji_date.require' => '请选择业绩日期',
'yeji_date.dateFormat' => '业绩日期格式错误',
'media_source.require' => '请填写自媒体来源',
'media_source.max' => '自媒体来源不能超过120个字符',
'add_fans_count.require' => '请填写加粉数',
'add_fans_count.integer' => '加粉数格式错误',
'add_fans_count.egt' => '加粉数不能小于0',
'remark.max' => '备注不能超过255个字符',
];
public function sceneAdd()
{
return $this->remove('id', true);
}
public function sceneEdit()
{
return $this->remove('yeji_date', true)->remove('media_source', true);
}
public function sceneDetail()
{
return $this->only(['id']);
}
public function sceneDelete()
{
return $this->only(['id']);
}
public function checkExists($value)
{
$model = PersonalYeji::find($value);
if (!$model) {
return '记录不存在';
}
return true;
}
}
@@ -14,6 +14,7 @@ class PrescriptionLibraryValidate extends BaseValidate
protected $rule = [
'id' => 'require|number',
'prescription_name' => 'require|max:100',
'formula_type' => 'in:主方,辅方',
'herbs' => 'require|array',
'is_public' => 'in:0,1'
];
@@ -23,6 +24,7 @@ class PrescriptionLibraryValidate extends BaseValidate
'id.number' => '处方ID必须为数字',
'prescription_name.require' => '处方名称不能为空',
'prescription_name.max' => '处方名称最多100个字符',
'formula_type.in' => '处方类型只能是主方或辅方',
'herbs.require' => '药材列表不能为空',
'herbs.array' => '药材列表格式错误',
'is_public.in' => '是否公开参数错误'
@@ -33,7 +35,7 @@ class PrescriptionLibraryValidate extends BaseValidate
*/
public function sceneAdd()
{
return $this->only(['prescription_name', 'herbs', 'is_public']);
return $this->only(['prescription_name', 'formula_type', 'herbs', 'is_public']);
}
/**
@@ -41,7 +43,7 @@ class PrescriptionLibraryValidate extends BaseValidate
*/
public function sceneEdit()
{
return $this->only(['id', 'prescription_name', 'herbs', 'is_public']);
return $this->only(['id', 'prescription_name', 'formula_type', 'herbs', 'is_public']);
}
/**
@@ -41,7 +41,7 @@ class PrescriptionValidate extends BaseValidate
'patient_name', 'gender', 'age',
'visit_no', 'prescription_date', 'tongue', 'tongue_image', 'pulse',
'pulse_condition', 'clinical_diagnosis', 'herbs', 'dose_count', 'dose_unit',
'usage_days', 'times_per_day', 'usage_instruction', 'usage_time', 'usage_way', 'dietary_taboo',
'usage_days', 'times_per_day', 'aux_usage', 'usage_instruction', 'usage_time', 'usage_way', 'dietary_taboo',
'usage_notes', 'doctor_name', 'is_shared', 'visible_role_ids',
'diagnosis_id', 'appointment_id', 'audit_status',
]);
@@ -54,7 +54,7 @@ class PrescriptionValidate extends BaseValidate
'patient_name', 'gender', 'age',
'visit_no', 'prescription_date', 'tongue', 'tongue_image', 'pulse',
'pulse_condition', 'clinical_diagnosis', 'herbs', 'dose_count', 'dose_unit',
'usage_days', 'times_per_day', 'usage_instruction', 'usage_time', 'usage_way', 'dietary_taboo',
'usage_days', 'times_per_day', 'aux_usage', 'usage_instruction', 'usage_time', 'usage_way', 'dietary_taboo',
'usage_notes', 'doctor_name', 'is_shared', 'visible_role_ids', 'diagnosis_id',
]);
}
@@ -24,6 +24,7 @@ use think\console\Output;
* php think gancao:sync-logistics 默认拉 100 单
* php think gancao:sync-logistics --limit=200 自定义拉取上限
* php think gancao:sync-logistics --order-id=123 只跑指定订单
* php think gancao:sync-logistics -t SF1234567890 按快递单号走快递100 查询并落库
* php think gancao:sync-logistics --detail 打印每单详细
*
* 建议 crontab(每 30 分钟执行一次):
@@ -40,6 +41,7 @@ class GancaoSyncLogisticsRoute extends Command
->setDescription('同步甘草订单的物流路由(GET_TASK_ROUTE_LIST)到本地物流追踪表')
->addOption('limit', 'l', Option::VALUE_OPTIONAL, '本次最多处理多少条订单', 100)
->addOption('order-id', null, Option::VALUE_OPTIONAL, '只同步指定 prescription_order.id', null)
->addOption('tracking-number', 't', Option::VALUE_REQUIRED, '按快递单号走快递100 查询并落库')
->addOption('detail', 'd', Option::VALUE_NONE, '打印每单详细结果');
}
@@ -48,26 +50,43 @@ class GancaoSyncLogisticsRoute extends Command
$limit = max(1, (int) $input->getOption('limit'));
$onlyOrderId = $input->getOption('order-id');
$onlyOrderId = $onlyOrderId !== null ? (int) $onlyOrderId : null;
$trackingNumber = trim((string) $input->getOption('tracking-number'));
$verbose = (bool) $input->getOption('detail');
if ($trackingNumber !== '' && $onlyOrderId !== null) {
$output->error('请勿同时使用 --tracking-number 与 --order-id');
return 1;
}
$output->writeln('========================================');
$output->writeln('甘草物流路由同步');
$output->writeln($trackingNumber !== '' ? '快递100 物流查询' : '甘草物流路由同步');
$output->writeln('========================================');
if (!GancaoScmRecipelService::isConfigured()) {
if ($trackingNumber === '' && !GancaoScmRecipelService::isConfigured()) {
$output->error('甘草 SCM 未配置:' . GancaoScmRecipelService::whyNotConfigured());
return 1;
}
$start = microtime(true);
$output->writeln('开始同步...limit=' . $limit . ($onlyOrderId ? ', order_id=' . $onlyOrderId : '') . '');
if ($trackingNumber !== '') {
$output->writeln('开始查询...(快递100tracking_number=' . $trackingNumber . '');
} else {
$output->writeln('开始同步...limit=' . $limit . ($onlyOrderId ? ', order_id=' . $onlyOrderId : '') . '');
}
try {
$stats = GancaoLogisticsRouteService::syncBatch($limit, $onlyOrderId);
$recon = ExpressTrackingService::reconcileAssistantReleaseForShippedPrescriptionOrders(200);
$stats['reconcile_cleared'] = (int) ($recon['cleared'] ?? 0);
$stats['reconcile_scanned'] = (int) ($recon['scanned'] ?? 0);
$stats['reconcile_lines'] = $recon['lines'] ?? [];
if ($trackingNumber !== '') {
$stats = ExpressTrackingService::queryKuaidiByTrackingNumber($trackingNumber);
$stats['reconcile_cleared'] = 0;
$stats['reconcile_scanned'] = 0;
$stats['reconcile_lines'] = [];
} else {
$stats = GancaoLogisticsRouteService::syncBatch($limit, $onlyOrderId);
$recon = ExpressTrackingService::reconcileAssistantReleaseForShippedPrescriptionOrders(2000);
$stats['reconcile_cleared'] = (int) ($recon['cleared'] ?? 0);
$stats['reconcile_scanned'] = (int) ($recon['scanned'] ?? 0);
$stats['reconcile_lines'] = $recon['lines'] ?? [];
}
} catch (\Throwable $e) {
$output->error('同步异常:' . $e->getMessage());
return 1;
@@ -81,7 +100,7 @@ class GancaoSyncLogisticsRoute extends Command
foreach ($stats['details'] as $row) {
$tag = !empty($row['success']) ? '[OK]' : '[FAIL]';
$line = sprintf(
'%s order_id=%s order_no=%s app_order_no=%s tn=%s state=%s traces=+%s msg=%s',
'%s order_id=%s order_no=%s app_order_no=%s tn=%s state=%s traces=+%s source=%s msg=%s',
$tag,
$row['order_id'] ?? '',
$row['order_no'] ?? '',
@@ -89,6 +108,7 @@ class GancaoSyncLogisticsRoute extends Command
$row['tracking_number'] ?? '',
$row['state'] ?? '',
$row['traces'] ?? 0,
$row['source'] ?? '',
$row['message'] ?? ''
);
$output->writeln($line);
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace app\common\model\stats;
use app\common\model\BaseModel;
use think\model\concern\SoftDelete;
class PersonalAccountCost extends BaseModel
{
use SoftDelete;
protected $name = 'personal_account_cost';
protected $deleteTime = 'delete_time';
protected $autoWriteTimestamp = true;
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
}
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace app\common\model\stats;
use app\common\model\BaseModel;
use think\model\concern\SoftDelete;
class PersonalYeji extends BaseModel
{
use SoftDelete;
protected $name = 'personal_yeji';
protected $deleteTime = 'delete_time';
protected $autoWriteTimestamp = true;
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
}
+1 -1
View File
@@ -18,7 +18,7 @@ class Prescription extends BaseModel
protected $deleteTime = 'delete_time';
protected $dateFormat = false;
protected $json = ['herbs', 'case_record'];
protected $json = ['herbs', 'case_record', 'aux_usage'];
protected $jsonAssoc = true;
// 字段类型转换
+148 -16
View File
@@ -45,6 +45,7 @@ class ExpressTrackService
$carrier = $resolved['carrier'];
$kuaidiCom = $resolved['kuaidi_com'];
$label = $resolved['label'];
$comCandidates = self::kuaidiComCandidates($kuaidiCom, $num);
$officialUrl = self::buildOfficialUrl($carrier, $num);
@@ -75,6 +76,74 @@ class ExpressTrackService
return $out;
}
$lastFail = null;
foreach ($comCandidates as $tryCom) {
$tryOut = self::queryKuaidiOnce($cfg, $tryCom, $num, $phoneForKuaidi, $carrier, $label);
if (!empty($tryOut['traces']) || ($tryOut['state'] ?? '') !== '') {
return $tryOut;
}
$lastFail = $tryOut;
}
return $lastFail ?? $out;
}
/**
* 根据运单号形态纠正承运商(避免 express_tracking 误存 sf 导致京东单查不出)
*/
public static function normalizeExpressCompanyCode(string $trackingNumber, string $storedCompany = 'auto'): string
{
$byNumber = self::detectCarrierFromNumber($trackingNumber);
if ($byNumber === null) {
$ec = strtolower(trim($storedCompany));
return in_array($ec, ['sf', 'jd', 'jt', 'jtexpress', 'auto'], true) ? $ec : 'auto';
}
$ec = strtolower(trim($storedCompany));
$byEc = self::carrierFromExpressCode($ec);
if ($byEc !== null && $byEc['carrier'] !== $byNumber['carrier']) {
return $byNumber['carrier'];
}
return $byNumber['carrier'];
}
/**
* @param array<string, mixed> $cfg
* @return array{
* carrier: string,
* carrier_label: string,
* kuaidi_com: string,
* traces: list<array{time:string,context:string}>,
* state: string,
* state_text: string,
* source: string,
* hint: string,
* official_url: string
* }
*/
private static function queryKuaidiOnce(
array $cfg,
string $kuaidiCom,
string $num,
string $phoneForKuaidi,
string $carrier,
string $label
): array {
$officialUrl = self::buildOfficialUrl($carrier, $num);
$out = [
'carrier' => $carrier,
'carrier_label' => $label,
'kuaidi_com' => $kuaidiCom,
'traces' => [],
'state' => '',
'state_text' => '',
'source' => 'kuaidi100',
'hint' => '',
'official_url' => $officialUrl,
];
$paramArr = [
'com' => $kuaidiCom,
'num' => $num,
@@ -98,7 +167,7 @@ class ExpressTrackService
$raw = self::httpPostForm($url, $postBody);
if ($raw === null || $raw === '') {
$out['hint'] = '快递100接口无响应,请稍后重试或使用官网查询';
Log::warning('ExpressTrackService kuaidi100 empty response', ['num' => $num]);
Log::warning('ExpressTrackService kuaidi100 empty response', ['num' => $num, 'com' => $kuaidiCom]);
return $out;
}
@@ -106,7 +175,7 @@ class ExpressTrackService
$json = json_decode($raw, true);
if (!is_array($json)) {
$out['hint'] = '快递100返回异常,请使用官网查询';
Log::warning('ExpressTrackService kuaidi100 invalid json', ['raw' => mb_substr($raw, 0, 500)]);
Log::warning('ExpressTrackService kuaidi100 invalid json', ['raw' => mb_substr($raw, 0, 500), 'com' => $kuaidiCom]);
return $out;
}
@@ -114,19 +183,16 @@ class ExpressTrackService
if (isset($json['result']) && $json['result'] === false) {
$msg = (string) ($json['message'] ?? '查询失败');
$returnCode = (string) ($json['returnCode'] ?? '');
// 特殊处理"找不到对应公司"错误
if ($msg === '找不到对应公司' || $returnCode === '400') {
$out['hint'] = '快递100暂不支持该快递公司或编码错误,请使用下方官网链接查询';
} else {
$out['hint'] = $msg;
}
Log::info('ExpressTrackService kuaidi100 business fail', [
'message' => $msg,
'returnCode' => $returnCode,
'num' => $num,
'com' => $kuaidiCom
'com' => $kuaidiCom,
]);
return $out;
@@ -138,7 +204,7 @@ class ExpressTrackService
}
if (($json['message'] ?? '') !== 'ok' && $data === []) {
$out['hint'] = (string) ($json['message'] ?? '未查到轨迹');
Log::info('ExpressTrackService kuaidi100 no data', ['json' => $json]);
Log::info('ExpressTrackService kuaidi100 no data', ['json' => $json, 'com' => $kuaidiCom]);
return $out;
}
@@ -159,12 +225,35 @@ class ExpressTrackService
$out['traces'] = $traces;
$out['state'] = (string) ($json['state'] ?? '');
$out['state_text'] = self::stateText($out['state']);
$out['source'] = 'kuaidi100';
$out['hint'] = $traces === [] ? '暂无轨迹节点,单号可能尚未揽收' : '';
return $out;
}
/**
* @return list<string>
*/
private static function kuaidiComCandidates(string $primaryCom, string $num): array
{
$list = [$primaryCom];
$byNumber = self::detectCarrierFromNumber($num);
if ($byNumber !== null && !in_array($byNumber['kuaidi_com'], $list, true)) {
$list[] = $byNumber['kuaidi_com'];
}
if (preg_match('/^JDVE/i', strtoupper($num)) && !in_array('jd', $list, true)) {
$list[] = 'jd';
}
if (preg_match('/^(JD|JDV|JDK|JDEX)/i', strtoupper($num))) {
foreach (['jingdong', 'jd'] as $c) {
if (!in_array($c, $list, true)) {
$list[] = $c;
}
}
}
return array_values(array_unique(array_filter($list, static fn ($c) => $c !== '' && $c !== 'auto')));
}
/**
* 快递100「phone」入参:有手动覆盖且不少于 4 位时用覆盖;否则用订单收货号码。
* 对 11 位及以上数字取后 11 位作为手机号(去掉可能的前缀符号位)。
@@ -191,32 +280,75 @@ class ExpressTrackService
}
/**
* @return array{carrier: string, kuaidi_com: string, label: string}
* @return array{carrier: string, kuaidi_com: string, label: string}|null
*/
private static function resolveCarrier(string $expressCompany, string $num): array
private static function carrierFromExpressCode(string $expressCompany): ?array
{
$ec = strtolower(trim($expressCompany));
if ($ec === 'sf') {
if ($ec === 'sf' || $ec === 'shunfeng') {
return ['carrier' => 'sf', 'kuaidi_com' => self::KUAIDI_COM_SF, 'label' => '顺丰速运'];
}
if ($ec === 'jd') {
if ($ec === 'jd' || $ec === 'jingdong') {
return ['carrier' => 'jd', 'kuaidi_com' => self::KUAIDI_COM_JD, 'label' => '京东快递'];
}
if ($ec === 'jt' || $ec === 'jtexpress') {
return ['carrier' => 'jt', 'kuaidi_com' => self::KUAIDI_COM_JT, 'label' => '极兔速递'];
}
$u = strtoupper($num);
if (preg_match('/^SF\d/i', $num)) {
return null;
}
/**
* @return array{carrier: string, kuaidi_com: string, label: string}|null
*/
private static function detectCarrierFromNumber(string $num): ?array
{
$n = trim($num);
if ($n === '') {
return null;
}
$u = strtoupper($n);
if (preg_match('/^SF\d/i', $n)) {
return ['carrier' => 'sf', 'kuaidi_com' => self::KUAIDI_COM_SF, 'label' => '顺丰速运(单号识别)'];
}
if (preg_match('/^(JD|JDV|JDK|JDEX|JD[A-Z0-9])/i', $u)) {
if (preg_match('/^JDVE/i', $u)) {
return ['carrier' => 'jd', 'kuaidi_com' => self::KUAIDI_COM_JD, 'label' => '京东快递(单号识别)'];
}
if (preg_match('/^JT\d{13}$/i', $num)) {
if (preg_match('/^(JDK|JDV|JDEX)/i', $u) || preg_match('/^JD[A-Z0-9]{10,}/i', $u)) {
return ['carrier' => 'jd', 'kuaidi_com' => self::KUAIDI_COM_JD, 'label' => '京东物流(单号识别)'];
}
if (preg_match('/^JT\d{13}$/i', $n)) {
return ['carrier' => 'jt', 'kuaidi_com' => self::KUAIDI_COM_JT, 'label' => '极兔速递(单号识别)'];
}
return null;
}
/**
* @return array{carrier: string, kuaidi_com: string, label: string}
*/
private static function resolveCarrier(string $expressCompany, string $num): array
{
$byNumber = self::detectCarrierFromNumber($num);
$byEc = self::carrierFromExpressCode($expressCompany);
if ($byNumber !== null && $byEc !== null && $byEc['carrier'] !== $byNumber['carrier']) {
Log::info('ExpressTrackService carrier mismatch, prefer tracking number', [
'express_company' => $expressCompany,
'tracking_number' => $num,
'stored_carrier' => $byEc['carrier'],
'detected_carrier' => $byNumber['carrier'],
]);
return $byNumber;
}
if ($byEc !== null) {
return $byEc;
}
if ($byNumber !== null) {
return $byNumber;
}
return ['carrier' => 'auto', 'kuaidi_com' => 'auto', 'label' => '自动识别'];
}
@@ -59,7 +59,10 @@ class ExpressTrackingService
$tracking->order_id = (int) ($params['order_id'] ?? 0);
$tracking->order_type = (string) ($params['order_type'] ?? 'prescription');
$tracking->express_company = (string) ($params['express_company'] ?? 'auto');
$tracking->express_company = ExpressTrackService::normalizeExpressCompanyCode(
$trackingNumber,
(string) ($params['express_company'] ?? 'auto')
);
$tracking->recipient_phone = (string) ($params['recipient_phone'] ?? '');
$tracking->recipient_name = (string) ($params['recipient_name'] ?? '');
$tracking->recipient_address = (string) ($params['recipient_address'] ?? '');
@@ -78,6 +81,177 @@ class ExpressTrackingService
return $tracking;
}
/**
* 按快递单号走快递100 查询并落库(CLIgancao:sync-logistics -t
*
* @return array{total:int, success:int, failed:int, skipped:int, assistant_cleared:int, assistant_lines:list<string>, details:array<int, array<string,mixed>>}
*/
public static function queryKuaidiByTrackingNumber(string $trackingNumber): array
{
$stats = [
'total' => 0,
'success' => 0,
'failed' => 0,
'skipped' => 0,
'assistant_cleared' => 0,
'assistant_skipped_assign_log' => 0,
'assistant_lines' => [],
'details' => [],
];
$tn = trim($trackingNumber);
if ($tn === '') {
$stats['failed'] = 1;
$stats['details'][] = [
'success' => false,
'tracking_number' => '',
'message' => '快递单号不能为空',
];
return $stats;
}
$tracking = self::resolveTrackingByNumber($tn);
if (!$tracking) {
$stats['failed'] = 1;
$stats['details'][] = [
'success' => false,
'tracking_number' => $tn,
'message' => '未找到该快递单号对应的业务订单或物流追踪记录',
];
return $stats;
}
$stats['total'] = 1;
self::backfillRecipientPhoneFromPrescriptionOrder($tracking);
self::syncTrackingExpressCompanyFromNumber($tracking);
try {
$result = self::queryAndUpdate((int) $tracking->id, false);
$ok = self::isKuaidiQuerySuccessful($result);
$detail = [
'order_id' => (int) $tracking->order_id,
'tracking_number' => (string) $tracking->tracking_number,
'success' => $ok,
'message' => trim((string) ($result['hint'] ?? '')) ?: 'ok',
'traces' => count($result['traces'] ?? []),
'state' => (string) ($result['state_text'] ?? $tracking->current_state_text ?? ''),
'source' => (string) ($result['source'] ?? ''),
];
if ($ok) {
$stats['success'] = 1;
} else {
$stats['failed'] = 1;
}
$stats['details'][] = $detail;
} catch (\Throwable $e) {
$stats['failed'] = 1;
$stats['details'][] = [
'order_id' => (int) $tracking->order_id,
'tracking_number' => (string) $tracking->tracking_number,
'success' => false,
'message' => '异常:' . $e->getMessage(),
];
Log::error('queryKuaidiByTrackingNumber failed', [
'tracking_number' => $tn,
'error' => $e->getMessage(),
]);
}
return $stats;
}
/**
* 确保 express_tracking 存在(不发起查询)
*/
private static function resolveTrackingByNumber(string $trackingNumber): ?ExpressTracking
{
$tn = trim($trackingNumber);
if ($tn === '') {
return null;
}
$tracking = ExpressTracking::whereRaw('TRIM(`tracking_number`) = ?', [$tn])
->whereNull('delete_time')
->find();
$order = PrescriptionOrder::whereNull('delete_time')
->whereRaw('TRIM(`tracking_number`) = ?', [$tn])
->order('id', 'desc')
->find();
if ($tracking && $order) {
$dirty = false;
if ((int) $tracking->order_id !== (int) $order->id) {
$tracking->order_id = (int) $order->id;
$dirty = true;
}
if (trim((string) ($tracking->recipient_phone ?? '')) === '') {
$tracking->recipient_phone = (string) ($order->recipient_phone ?? '');
$dirty = true;
}
if ($dirty) {
$tracking->update_time = time();
$tracking->save();
}
return $tracking;
}
if ($tracking) {
self::backfillRecipientPhoneFromPrescriptionOrder($tracking);
return $tracking;
}
if (!$order) {
return null;
}
$now = time();
$tracking = new ExpressTracking();
$tracking->tracking_number = mb_substr($tn, 0, 80);
$tracking->create_time = $now;
$tracking->order_id = (int) $order->id;
$tracking->order_type = 'prescription';
$tracking->express_company = ExpressTrackService::normalizeExpressCompanyCode(
$tn,
(string) ($order->express_company ?? 'auto')
);
$tracking->recipient_phone = (string) ($order->recipient_phone ?? '');
$tracking->recipient_name = (string) ($order->recipient_name ?? '');
$tracking->recipient_address = (string) ($order->shipping_address ?? '');
$tracking->next_update_time = $now;
$tracking->update_time = $now;
$tracking->save();
return $tracking;
}
/**
* @param array<string, mixed>|null $result
*/
private static function isKuaidiQuerySuccessful(?array $result): bool
{
if (!is_array($result)) {
return false;
}
$source = (string) ($result['source'] ?? '');
if ($source !== 'kuaidi100') {
return false;
}
$hint = trim((string) ($result['hint'] ?? ''));
if ($hint === '') {
return true;
}
if (str_contains($hint, '暂无轨迹')) {
return true;
}
return false;
}
/**
* 查询并更新物流信息
*
@@ -96,13 +270,14 @@ class ExpressTrackingService
}
self::backfillRecipientPhoneFromPrescriptionOrder($tracking);
self::syncTrackingExpressCompanyFromNumber($tracking);
$startTime = microtime(true);
// 调用快递100查询(顺丰等单号需带收件人手机号后四位,见 ExpressTrackService
$result = ExpressTrackService::query(
$tracking->express_company,
$tracking->tracking_number,
(string) $tracking->express_company,
(string) $tracking->tracking_number,
(string) $tracking->recipient_phone
);
@@ -547,6 +722,27 @@ class ExpressTrackingService
}
}
/**
* 运单号与 express_company 不一致时按单号纠正(如京东单误存 sf)
*/
private static function syncTrackingExpressCompanyFromNumber(ExpressTracking $tracking): void
{
$num = trim((string) $tracking->tracking_number);
if ($num === '') {
return;
}
$normalized = ExpressTrackService::normalizeExpressCompanyCode(
$num,
(string) ($tracking->express_company ?? 'auto')
);
if ($normalized === (string) $tracking->express_company) {
return;
}
$tracking->express_company = $normalized;
$tracking->update_time = time();
$tracking->save();
}
/**
* 保存轨迹明细
*/
@@ -470,54 +470,62 @@ final class GancaoLogisticsRouteService
$orders = $q->order('id', 'desc')->limit($limit)->select();
foreach ($orders as $order) {
$stats['total']++;
try {
$r = self::syncOne($order);
$detail = [
'order_id' => (int) $order->id,
'order_no' => (string) $order->order_no,
'app_order_no' => (string) $order->gancao_reciperl_order_no,
'tracking_number' => (string) $order->tracking_number,
'success' => $r['success'],
'message' => $r['message'],
'traces' => $r['traces_count'],
'state' => $r['state'],
];
if ($r['success']) {
$stats['success']++;
if (!empty($r['assistant_sync']) && is_array($r['assistant_sync'])) {
$sync = $r['assistant_sync'];
$act = (string) ($sync['action'] ?? '');
if ($act === 'cleared') {
$stats['assistant_cleared']++;
$stats['assistant_lines'][] = sprintf(
'[移除医助+指派日志][甘草路由] 诊单=%d 业务订单=%d 运单=%s 原医助ID=%s 履约状态=%d',
(int) ($sync['diagnosis_id'] ?? 0),
(int) ($sync['prescription_order_id'] ?? 0),
(string) ($sync['tracking_number'] ?? ''),
(string) ($sync['former_assistant_id'] ?? ''),
(int) ($sync['fulfillment_status'] ?? 0)
);
}
}
} else {
$stats['failed']++;
}
$stats['details'][] = $detail;
} catch (\Throwable $e) {
$stats['failed']++;
$stats['details'][] = [
'order_id' => (int) $order->id,
'success' => false,
'message' => '异常:' . $e->getMessage(),
];
Log::error('Gancao route sync exception: ' . $e->getMessage(), [
'order_id' => (int) $order->id,
'trace' => $e->getTraceAsString(),
]);
}
self::appendSyncOneResult($stats, $order);
}
return $stats;
}
/**
* @param array{total:int, success:int, failed:int, skipped:int, assistant_cleared:int, assistant_skipped_assign_log:int, assistant_lines:list<string>, details:array<int, array<string,mixed>>} $stats
*/
private static function appendSyncOneResult(array &$stats, PrescriptionOrder $order): void
{
$stats['total']++;
try {
$r = self::syncOne($order);
$detail = [
'order_id' => (int) $order->id,
'order_no' => (string) $order->order_no,
'app_order_no' => (string) $order->gancao_reciperl_order_no,
'tracking_number' => (string) $order->tracking_number,
'success' => $r['success'],
'message' => $r['message'],
'traces' => $r['traces_count'],
'state' => $r['state'],
];
if ($r['success']) {
$stats['success']++;
if (!empty($r['assistant_sync']) && is_array($r['assistant_sync'])) {
$sync = $r['assistant_sync'];
$act = (string) ($sync['action'] ?? '');
if ($act === 'cleared') {
$stats['assistant_cleared']++;
$stats['assistant_lines'][] = sprintf(
'[移除医助+指派日志][甘草路由] 诊单=%d 业务订单=%d 运单=%s 原医助ID=%s 履约状态=%d',
(int) ($sync['diagnosis_id'] ?? 0),
(int) ($sync['prescription_order_id'] ?? 0),
(string) ($sync['tracking_number'] ?? ''),
(string) ($sync['former_assistant_id'] ?? ''),
(int) ($sync['fulfillment_status'] ?? 0)
);
}
}
} else {
$stats['failed']++;
}
$stats['details'][] = $detail;
} catch (\Throwable $e) {
$stats['failed']++;
$stats['details'][] = [
'order_id' => (int) $order->id,
'success' => false,
'message' => '异常:' . $e->getMessage(),
];
Log::error('Gancao route sync exception: ' . $e->getMessage(), [
'order_id' => (int) $order->id,
'trace' => $e->getTraceAsString(),
]);
}
}
}
+5
View File
@@ -123,6 +123,11 @@ return [
// 订单管理列表(order/index):以下角色 ID + root 可查看全部订单,其余仅本人创建
'order_list_view_all_roles' => [0, 3, 4, 9, 6],
// 自录转化统计(stats.self_input / personal_yeji / personal_account_cost):
// 以下角色 ID + root 在列表与总览中可见全部录入人的业绩/账户消耗(不受角色 data_scope 收窄)。
// 编辑/删除由菜单按钮权限(stats.personal_yeji/edit 等)控制,不在此配置。
'self_input_stats_view_all_roles' => [0, 3, 4, 9, 6],
// 业务订单列表金额统计:医助角色 ID;非支付审核白名单的医助仅统计其诊单 assistant_id=本人 的业绩
'prescription_order_stats_assistant_role_id' => 2,
@@ -2,6 +2,7 @@
CREATE TABLE IF NOT EXISTS `zyt_prescription_library` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`prescription_name` varchar(100) NOT NULL DEFAULT '' COMMENT '处方名称',
`formula_type` varchar(20) NOT NULL DEFAULT '主方' COMMENT '处方类型:主方、辅方',
`herbs` text COMMENT '药材列表JSON[{name, dosage}]',
`is_public` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否公开:0-仅自己可见 1-所有人可见',
`creator_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '创建人ID',
@@ -1 +1 @@
import r from"./error-wyGGmxC3.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-DFTWCWyi.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-HOEUG8sr.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-D2tYw7RM.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};
import r from"./error-CmgM8V0D.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-DFTWCWyi.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-HOEUG8sr.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-KChY3YtM.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-wyGGmxC3.js";import{f as r,ak as t,I as m,a as p}from"./@vue/runtime-core-C6bnekPw.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-D2tYw7RM.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};
import o from"./error-CmgM8V0D.js";import{f as r,ak as t,I as m,a as p}from"./@vue/runtime-core-C6bnekPw.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-KChY3YtM.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{M as x,N as y,r as I,d as C,L as $}from"./element-plus-DFTWCWyi.js";import{W as D}from"./@element-plus/icons-vue-HOEUG8sr.js";import{a3 as L}from"./tcm-C3dQ3CSx.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-D2tYw7RM.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=C,r=I,s=x,S=$;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 C,L as $}from"./element-plus-DFTWCWyi.js";import{W as D}from"./@element-plus/icons-vue-HOEUG8sr.js";import{a3 as L}from"./tcm-8uQ_Iq7v.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-KChY3YtM.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=C,r=I,s=x,S=$;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 +1 @@
import{i as L,L as T,N as V,T as D,M as z,R as M}from"./element-plus-DFTWCWyi.js";import{ab as O}from"./tcm-C3dQ3CSx.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-D2tYw7RM.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-HOEUG8sr.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,b=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=>{b("view",e)},B=()=>{b("openPrescription")};return F(()=>{u()}),R(()=>_.diagnosisId,()=>{u()}),x({refresh:u}),(e,t)=>{const h=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(h,{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(h,{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-DFTWCWyi.js";import{ab as O}from"./tcm-8uQ_Iq7v.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-KChY3YtM.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-HOEUG8sr.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,b=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=>{b("view",e)},B=()=>{b("openPrescription")};return F(()=>{u()}),R(()=>_.diagnosisId,()=>{u()}),x({refresh:u}),(e,t)=>{const h=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(h,{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(h,{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
@@ -1,2 +1,2 @@
import{R as W,v as Z,d as q,a as K}from"./element-plus-DFTWCWyi.js";import{_ as Y}from"./picker-DxFyzHJw.js";import{e as ee,c as te,i as S,_ as ie}from"./index-D2tYw7RM.js";import{s as A}from"./@vue/runtime-dom-DDAG46FW.js";import{b as B,G as se}from"./@element-plus/icons-vue-HOEUG8sr.js";import{d as oe,a as R}from"./patient-jQ_Wc7vw.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-CKd1YhbK.js";import"./index-ZaSXEaDt.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./index-BeKT8md7.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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(`
import{R as W,v as Z,d as q,a as K}from"./element-plus-DFTWCWyi.js";import{_ as Y}from"./picker-DBkge4jE.js";import{e as ee,c as te,i as S,_ as ie}from"./index-KChY3YtM.js";import{s as A}from"./@vue/runtime-dom-DDAG46FW.js";import{b as B,G as se}from"./@element-plus/icons-vue-HOEUG8sr.js";import{d as oe,a as R}from"./patient-BL9wH_Vk.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-C0sC4Td0.js";import"./index-Ci_-lYZD.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./index-B1yDaEur.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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-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-D2tYw7RM.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-DFTWCWyi.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./@element-plus/icons-vue-HOEUG8sr.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};
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-KChY3YtM.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-DFTWCWyi.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./@element-plus/icons-vue-HOEUG8sr.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};
@@ -1 +1 @@
import{_ as L}from"./element-plus-DFTWCWyi.js";import B from"./RecordingVideoPlayer-BcjhEcT4.js";import{e as H,_ as I}from"./index-D2tYw7RM.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-HOEUG8sr.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};
import{_ as L}from"./element-plus-DFTWCWyi.js";import B from"./RecordingVideoPlayer-_86CXsp7.js";import{e as H,_ as I}from"./index-KChY3YtM.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-HOEUG8sr.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};
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-DFTWCWyi.js";import{U as T}from"./tcm-C3dQ3CSx.js";import{i as C,_ as E}from"./index-D2tYw7RM.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-HOEUG8sr.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"},U={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-DFTWCWyi.js";import{U as T}from"./tcm-8uQ_Iq7v.js";import{i as C,_ as E}from"./index-KChY3YtM.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-HOEUG8sr.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"},U={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",U,[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-CCSYSrV5.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-CKd1YhbK.js";import"./index-D2tYw7RM.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};
import{_ as o}from"./account-adjust.vue_vue_type_script_setup_true_lang-C8RvB0M5.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-C0sC4Td0.js";import"./index-KChY3YtM.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};
@@ -1 +1 @@
import{D as h,B as q,G as B,I,C as D}from"./element-plus-DFTWCWyi.js";import{_ as F}from"./index-CKd1YhbK.js";import{i as b}from"./index-D2tYw7RM.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 _};
import{D as h,B as q,G as B,I,C as D}from"./element-plus-DFTWCWyi.js";import{_ as F}from"./index-C0sC4Td0.js";import{i as b}from"./index-KChY3YtM.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 +1 @@
import{_ as o}from"./add-nav.vue_vue_type_script_setup_true_lang-WWde2pX5.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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};
import{_ as o}from"./add-nav.vue_vue_type_script_setup_true_lang-O5VeJfV0.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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-DFTWCWyi.js";import{_ as $}from"./index-BeKT8md7.js";import{_ as z}from"./picker-N14js34s.js";import{_ as A}from"./picker-DxFyzHJw.js";import{c as D,i as r}from"./index-D2tYw7RM.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 _};
import{C as E,B,g as C,i as N}from"./element-plus-DFTWCWyi.js";import{_ as $}from"./index-B1yDaEur.js";import{_ as z}from"./picker-BV8NrMs7.js";import{_ as A}from"./picker-DBkge4jE.js";import{c as D,i as r}from"./index-KChY3YtM.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 _};
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{r as n}from"./index-D2tYw7RM.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-KChY3YtM.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
@@ -1 +1 @@
import{r as e}from"./index-D2tYw7RM.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-KChY3YtM.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};
@@ -1 +1 @@
import{m as b,l as c,D as V}from"./element-plus-DFTWCWyi.js";import{_ as l}from"./menu-set.vue_vue_type_script_setup_true_lang-CLWbq8zX.js";import{f as v,ak as x,I as k,J as E,a as o,aN as e,F as g,A as w}from"./@vue/runtime-core-C6bnekPw.js";import{y as r}from"./@vue/reactivity-DiY1c2vO.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-HOEUG8sr.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-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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";const Bt=v({__name:"attr",props:{modelValue:{type:Object,default:()=>({nav:[],menu:{}})}},emits:["update:modelValue"],setup(n,{emit:s}){const u=n,d=s,m=w({get(){return u.modelValue},set(i){d("update:modelValue",i)}});return(i,t)=>{const a=c,f=b,_=V;return x(),k(g,null,[t[2]||(t[2]=E("div",{class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2"}," pc导航设置 ",-1)),o(_,{class:"mt-4","label-width":"70px"},{default:e(()=>[o(f,{"model-value":"nav"},{default:e(()=>[o(a,{label:"主导航设置",name:"nav"},{default:e(()=>[o(l,{modelValue:r(m).nav,"onUpdate:modelValue":t[0]||(t[0]=p=>r(m).nav=p)},null,8,["modelValue"])]),_:1}),o(a,{label:"菜单设置",name:"menu"},{default:e(()=>[o(l,{modelValue:r(m).menu,"onUpdate:modelValue":t[1]||(t[1]=p=>r(m).menu=p)},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})],64)}}});export{Bt as default};
import{m as b,l as c,D as V}from"./element-plus-DFTWCWyi.js";import{_ as l}from"./menu-set.vue_vue_type_script_setup_true_lang-C5BeuNNI.js";import{f as v,ak as x,I as k,J as E,a as o,aN as e,F as g,A as w}from"./@vue/runtime-core-C6bnekPw.js";import{y as r}from"./@vue/reactivity-DiY1c2vO.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-HOEUG8sr.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-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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";const Bt=v({__name:"attr",props:{modelValue:{type:Object,default:()=>({nav:[],menu:{}})}},emits:["update:modelValue"],setup(n,{emit:s}){const u=n,d=s,m=w({get(){return u.modelValue},set(i){d("update:modelValue",i)}});return(i,t)=>{const a=c,f=b,_=V;return x(),k(g,null,[t[2]||(t[2]=E("div",{class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2"}," pc导航设置 ",-1)),o(_,{class:"mt-4","label-width":"70px"},{default:e(()=>[o(f,{"model-value":"nav"},{default:e(()=>[o(a,{label:"主导航设置",name:"nav"},{default:e(()=>[o(l,{modelValue:r(m).nav,"onUpdate:modelValue":t[0]||(t[0]=p=>r(m).nav=p)},null,8,["modelValue"])]),_:1}),o(a,{label:"菜单设置",name:"menu"},{default:e(()=>[o(l,{modelValue:r(m).menu,"onUpdate:modelValue":t[1]||(t[1]=p=>r(m).menu=p)},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})],64)}}});export{Bt as default};
@@ -1 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-iJR1KunE.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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"./index.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";export{o as default};
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-BHWqxH2A.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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"./index.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";export{o as default};
@@ -1 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CUtir7Zg.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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};
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CB76asNh.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-tFPYUz-8.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-WWde2pX5.js";import"./index-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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};
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-IZhLnJ-d.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-O5VeJfV0.js";import"./index-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CPT9q7MW.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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};
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CyyWr3Pg.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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
@@ -1 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CElAegNn.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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"./picker-DxFyzHJw.js";import"./index-CKd1YhbK.js";import"./index-D2tYw7RM.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"./index-ZaSXEaDt.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./index-BeKT8md7.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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";export{o as default};
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-B5rBHQDP.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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"./picker-DBkge4jE.js";import"./index-C0sC4Td0.js";import"./index-KChY3YtM.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"./index-Ci_-lYZD.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./index-B1yDaEur.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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";export{o as default};
@@ -1 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-B8_Edv_u.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./picker-DxFyzHJw.js";import"./index-CKd1YhbK.js";import"./index-D2tYw7RM.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";import"./index-ZaSXEaDt.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./index-BeKT8md7.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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";export{o as default};
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-B66Dlx5J.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";import"./@vueuse/core-1S4fJlii.js";import"./@vueuse/shared-Cl3lVqjz.js";import"./picker-DBkge4jE.js";import"./index-C0sC4Td0.js";import"./index-KChY3YtM.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";import"./index-Ci_-lYZD.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./index-B1yDaEur.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr-setting.vue_vue_type_script_setup_true_lang-C-dHkLKv.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-CYlyAds0.js";import"./attr-Di_OUGQt.js";import"./index-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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"./content.vue_vue_type_script_setup_true_lang-CIvsgz4M.js";import"./decoration-img-FVkY_FjR.js";import"./attr.vue_vue_type_script_setup_true_lang-B5rBHQDP.js";import"./content-DqlG1Qhj.js";import"./attr.vue_vue_type_script_setup_true_lang-CyyWr3Pg.js";import"./content.vue_vue_type_script_setup_true_lang-sUMWONse.js";import"./attr.vue_vue_type_script_setup_true_lang-IZhLnJ-d.js";import"./add-nav.vue_vue_type_script_setup_true_lang-O5VeJfV0.js";import"./content-D4w391MP.js";import"./attr.vue_vue_type_script_setup_true_lang-jNLVWayY.js";import"./content.vue_vue_type_script_setup_true_lang-BTThMPtP.js";import"./attr.vue_vue_type_script_setup_true_lang-DnkDutJb.js";import"./content-Bwf3C839.js";import"./decoration-DXXw_AHy.js";import"./attr.vue_vue_type_script_setup_true_lang-B66Dlx5J.js";import"./index.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";import"./content-Cc7-_bAu.js";import"./content.vue_vue_type_script_setup_true_lang-5h6I_409.js";import"./attr.vue_vue_type_script_setup_true_lang-ChKJn1wI.js";import"./content-DQrmF-lb.js";import"./attr.vue_vue_type_script_setup_true_lang-CB76asNh.js";import"./content.vue_vue_type_script_setup_true_lang-44DelfSG.js";import"./attr.vue_vue_type_script_setup_true_lang-9MDVGbdQ.js";import"./content-Hz2Sixh1.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr-setting.vue_vue_type_script_setup_true_lang-CcqmOpLe.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-CILCY8k3.js";import"./attr-BgmOOAYX.js";import"./index-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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"./content.vue_vue_type_script_setup_true_lang-BeC3Aoy5.js";import"./decoration-img-jVBtjpMX.js";import"./attr.vue_vue_type_script_setup_true_lang-CElAegNn.js";import"./content-BsniMxvl.js";import"./attr.vue_vue_type_script_setup_true_lang-CUtir7Zg.js";import"./content.vue_vue_type_script_setup_true_lang-DeepNYd9.js";import"./attr.vue_vue_type_script_setup_true_lang-DfMUuEpj.js";import"./add-nav.vue_vue_type_script_setup_true_lang-WWde2pX5.js";import"./content-AipRzubx.js";import"./attr.vue_vue_type_script_setup_true_lang-tFPYUz-8.js";import"./content.vue_vue_type_script_setup_true_lang-DV4JTE3o.js";import"./attr.vue_vue_type_script_setup_true_lang-DnkDutJb.js";import"./content-BSgZM3E_.js";import"./decoration-DYesnMfy.js";import"./attr.vue_vue_type_script_setup_true_lang-B8_Edv_u.js";import"./index.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";import"./content-CfPIfs0n.js";import"./content.vue_vue_type_script_setup_true_lang-CqF2cAS5.js";import"./attr.vue_vue_type_script_setup_true_lang-ChKJn1wI.js";import"./content-rEYbHELh.js";import"./attr.vue_vue_type_script_setup_true_lang-CPT9q7MW.js";import"./content.vue_vue_type_script_setup_true_lang-Bv66rmmf.js";import"./attr.vue_vue_type_script_setup_true_lang-9MDVGbdQ.js";import"./content-B8gmWcZJ.js";export{o as default};
@@ -1 +1 @@
import{J as y,s as g}from"./element-plus-DFTWCWyi.js";import{e as b}from"./index-CILCY8k3.js";import{f as x,ak as o,I as _,a as r,aN as c,J as h,G as i,K as w,at as k}from"./@vue/runtime-core-C6bnekPw.js";import{Q as v}from"./@vue/shared-mAAVTE9n.js";import{y as C}from"./@vue/reactivity-DiY1c2vO.js";const B={class:"pages-setting"},E={class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2 text-xl font-medium"},V=x({__name:"attr-setting",props:{widget:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(e,{emit:m}){const d=m,p=a=>{d("update:content",a)};return(a,N)=>{const f=y,u=g;return o(),_("div",B,[r(f,{shadow:"never",class:"!border-none flex"},{default:c(()=>{var t;return[h("div",E,v((t=e.widget)==null?void 0:t.title),1)]}),_:1}),r(u,{class:"w-full",style:{height:"calc(100% - 60px)"}},{default:c(()=>{var t,n,s,l;return[(o(),i(w,null,[(o(),i(k((n=C(b)[(t=e.widget)==null?void 0:t.name])==null?void 0:n.attr),{content:(s=e.widget)==null?void 0:s.content,styles:(l=e.widget)==null?void 0:l.styles,type:e.type,"onUpdate:content":p},null,40,["content","styles","type"]))],1024))]}),_:1})])}}});export{V as _};
import{J as y,s as g}from"./element-plus-DFTWCWyi.js";import{e as b}from"./index-CYlyAds0.js";import{f as x,ak as o,I as _,a as r,aN as c,J as h,G as i,K as w,at as k}from"./@vue/runtime-core-C6bnekPw.js";import{Q as v}from"./@vue/shared-mAAVTE9n.js";import{y as C}from"./@vue/reactivity-DiY1c2vO.js";const B={class:"pages-setting"},E={class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2 text-xl font-medium"},V=x({__name:"attr-setting",props:{widget:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(e,{emit:m}){const d=m,p=a=>{d("update:content",a)};return(a,N)=>{const f=y,u=g;return o(),_("div",B,[r(f,{shadow:"never",class:"!border-none flex"},{default:c(()=>{var t;return[h("div",E,v((t=e.widget)==null?void 0:t.title),1)]}),_:1}),r(u,{class:"w-full",style:{height:"calc(100% - 60px)"}},{default:c(()=>{var t,n,s,l;return[(o(),i(w,null,[(o(),i(k((n=C(b)[(t=e.widget)==null?void 0:t.name])==null?void 0:n.attr),{content:(s=e.widget)==null?void 0:s.content,styles:(l=e.widget)==null?void 0:l.styles,type:e.type,"onUpdate:content":p},null,40,["content","styles","type"]))],1024))]}),_:1})])}}});export{V as _};
@@ -1 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-DfMUuEpj.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-WWde2pX5.js";import"./index-BeKT8md7.js";import"./index-D2tYw7RM.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-N14js34s.js";import"./index-CKd1YhbK.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-CwArmJlj.js";import"./usePaging-VsbTxSU0.js";import"./picker-DxFyzHJw.js";import"./index-ZaSXEaDt.js";import"./index-Dj0bf9Bo.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-decZRjDJ.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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};
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-jNLVWayY.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-O5VeJfV0.js";import"./index-B1yDaEur.js";import"./index-KChY3YtM.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-BV8NrMs7.js";import"./index-C0sC4Td0.js";import"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import"./article-cpGUBMkD.js";import"./usePaging-VsbTxSU0.js";import"./picker-DBkge4jE.js";import"./index-Ci_-lYZD.js";import"./index-BBf-ecx3.js";import"./cos-js-sdk-v5-DSMN0LUT.js";import"./file-Ca5dbZgh.js";import"./index.vue_vue_type_script_setup_true_lang-x0oL2ShL.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{J as V,B as w,C as x,D as b}from"./element-plus-DFTWCWyi.js";import{_ as g}from"./picker-DxFyzHJw.js";import{f as k,ak as E,I as U,a as e,aN as n,J as y,A as B}from"./@vue/runtime-core-C6bnekPw.js";import{y as o}from"./@vue/reactivity-DiY1c2vO.js";const j=k({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(u,{emit:r}){const p=r,i=u,l=B({get:()=>i.content,set:d=>{p("update:content",d)}});return(d,t)=>{const s=x,m=w,_=g,c=V,f=b;return E(),U("div",null,[e(f,{"label-width":"90px",size:"large","label-position":"top"},{default:n(()=>[e(c,{shadow:"never",class:"!border-none flex mt-2"},{default:n(()=>[e(m,{label:"平台名称"},{default:n(()=>[e(s,{class:"w-[400px]","show-word-limit":"",maxlength:"20",modelValue:o(l).title,"onUpdate:modelValue":t[0]||(t[0]=a=>o(l).title=a)},null,8,["modelValue"])]),_:1}),e(m,{label:"客服二维码"},{default:n(()=>[y("div",null,[e(_,{modelValue:o(l).qrcode,"onUpdate:modelValue":t[1]||(t[1]=a=>o(l).qrcode=a),"exclude-domain":""},null,8,["modelValue"])])]),_:1}),e(m,{label:"备注"},{default:n(()=>[e(s,{class:"w-[400px]","show-word-limit":"",maxlength:"20",modelValue:o(l).remark,"onUpdate:modelValue":t[2]||(t[2]=a=>o(l).remark=a)},null,8,["modelValue"])]),_:1}),e(m,{label:"联系电话"},{default:n(()=>[e(s,{class:"w-[400px]",modelValue:o(l).mobile,"onUpdate:modelValue":t[3]||(t[3]=a=>o(l).mobile=a)},null,8,["modelValue"])]),_:1}),e(m,{label:"服务时间"},{default:n(()=>[e(s,{class:"w-[400px]","show-word-limit":"",maxlength:"20",modelValue:o(l).time,"onUpdate:modelValue":t[4]||(t[4]=a=>o(l).time=a)},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})])}}});export{j as _};
import{J as V,B as w,C as x,D as b}from"./element-plus-DFTWCWyi.js";import{_ as g}from"./picker-DBkge4jE.js";import{f as k,ak as E,I as U,a as e,aN as n,J as y,A as B}from"./@vue/runtime-core-C6bnekPw.js";import{y as o}from"./@vue/reactivity-DiY1c2vO.js";const j=k({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(u,{emit:r}){const p=r,i=u,l=B({get:()=>i.content,set:d=>{p("update:content",d)}});return(d,t)=>{const s=x,m=w,_=g,c=V,f=b;return E(),U("div",null,[e(f,{"label-width":"90px",size:"large","label-position":"top"},{default:n(()=>[e(c,{shadow:"never",class:"!border-none flex mt-2"},{default:n(()=>[e(m,{label:"平台名称"},{default:n(()=>[e(s,{class:"w-[400px]","show-word-limit":"",maxlength:"20",modelValue:o(l).title,"onUpdate:modelValue":t[0]||(t[0]=a=>o(l).title=a)},null,8,["modelValue"])]),_:1}),e(m,{label:"客服二维码"},{default:n(()=>[y("div",null,[e(_,{modelValue:o(l).qrcode,"onUpdate:modelValue":t[1]||(t[1]=a=>o(l).qrcode=a),"exclude-domain":""},null,8,["modelValue"])])]),_:1}),e(m,{label:"备注"},{default:n(()=>[e(s,{class:"w-[400px]","show-word-limit":"",maxlength:"20",modelValue:o(l).remark,"onUpdate:modelValue":t[2]||(t[2]=a=>o(l).remark=a)},null,8,["modelValue"])]),_:1}),e(m,{label:"联系电话"},{default:n(()=>[e(s,{class:"w-[400px]",modelValue:o(l).mobile,"onUpdate:modelValue":t[3]||(t[3]=a=>o(l).mobile=a)},null,8,["modelValue"])]),_:1}),e(m,{label:"服务时间"},{default:n(()=>[e(s,{class:"w-[400px]","show-word-limit":"",maxlength:"20",modelValue:o(l).time,"onUpdate:modelValue":t[4]||(t[4]=a=>o(l).time=a)},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})])}}});export{j as _};
@@ -1 +1 @@
import{J as E,B as C,G as F,I as N,C as B,D as z}from"./element-plus-DFTWCWyi.js";import{_ as G}from"./index.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";import{_ as I}from"./picker-DxFyzHJw.js";import{f as O,ak as r,G as s,aN as t,a as l,O as p,H as i,J as y,A as j}from"./@vue/runtime-core-C6bnekPw.js";import{y as a}from"./@vue/reactivity-DiY1c2vO.js";const T=O({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(m,{emit:g}){const b=g,x=m,o=j({get:()=>x.content,set:_=>{b("update:content",_)}});return(_,e)=>{const u=N,f=F,d=C,k=B,V=I,v=G,U=E,w=z;return r(),s(w,{ref:"form","label-width":"80px",size:"large"},{default:t(()=>[l(U,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>[l(d,{label:"页面标题"},{default:t(()=>[l(f,{modelValue:a(o).title_type,"onUpdate:modelValue":e[0]||(e[0]=n=>a(o).title_type=n)},{default:t(()=>[l(u,{value:"1"},{default:t(()=>[...e[7]||(e[7]=[p("文字",-1)])]),_:1}),l(u,{value:"2"},{default:t(()=>[...e[8]||(e[8]=[p("图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),m.content.title_type==1?(r(),s(d,{key:0},{default:t(()=>[l(k,{modelValue:a(o).title,"onUpdate:modelValue":e[1]||(e[1]=n=>a(o).title=n),maxlength:"8","show-word-limit":"",class:"w-[300px]",placeholder:"请输入页面标题"},null,8,["modelValue"])]),_:1})):i("",!0),m.content.title_type==2?(r(),s(d,{key:1},{default:t(()=>[l(V,{modelValue:a(o).title_img,"onUpdate:modelValue":e[2]||(e[2]=n=>a(o).title_img=n),limit:1,size:"100px"},null,8,["modelValue"]),e[9]||(e[9]=y("div",{class:"form-tips"},"建议图片尺寸:300px*40px",-1))]),_:1})):i("",!0),m.content.title_type==1?(r(),s(d,{key:2,label:"文字颜色"},{default:t(()=>[l(f,{modelValue:a(o).text_color,"onUpdate:modelValue":e[3]||(e[3]=n=>a(o).text_color=n)},{default:t(()=>[l(u,{value:"1"},{default:t(()=>[...e[10]||(e[10]=[p("白色",-1)])]),_:1}),l(u,{value:"2"},{default:t(()=>[...e[11]||(e[11]=[p("黑色",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1})):i("",!0),l(d,{label:"页面背景"},{default:t(()=>[l(f,{modelValue:a(o).bg_type,"onUpdate:modelValue":e[4]||(e[4]=n=>a(o).bg_type=n)},{default:t(()=>[l(u,{value:"1"},{default:t(()=>[...e[12]||(e[12]=[p("背景颜色",-1)])]),_:1}),l(u,{value:"2"},{default:t(()=>[...e[13]||(e[13]=[p("背景图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),m.content.bg_type==1?(r(),s(d,{key:3},{default:t(()=>[l(v,{modelValue:a(o).bg_color,"onUpdate:modelValue":e[5]||(e[5]=n=>a(o).bg_color=n),"reset-color":"#F5F5F5"},null,8,["modelValue"])]),_:1})):i("",!0),m.content.bg_type==2?(r(),s(d,{key:4},{default:t(()=>[l(V,{modelValue:a(o).bg_image,"onUpdate:modelValue":e[6]||(e[6]=n=>a(o).bg_image=n),limit:1,size:"100px"},null,8,["modelValue"]),e[14]||(e[14]=y("div",{class:"form-tips"},"建议图片尺寸:750px*高度不限",-1))]),_:1})):i("",!0)]),_:1})]),_:1},512)}}});export{T as _};
import{J as E,B as C,G as F,I as N,C as B,D as z}from"./element-plus-DFTWCWyi.js";import{_ as G}from"./index.vue_vue_type_script_setup_true_lang-3vCdLVB9.js";import{_ as I}from"./picker-DBkge4jE.js";import{f as O,ak as r,G as s,aN as t,a as l,O as p,H as i,J as y,A as j}from"./@vue/runtime-core-C6bnekPw.js";import{y as a}from"./@vue/reactivity-DiY1c2vO.js";const T=O({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(m,{emit:g}){const b=g,x=m,o=j({get:()=>x.content,set:_=>{b("update:content",_)}});return(_,e)=>{const u=N,f=F,d=C,k=B,V=I,v=G,U=E,w=z;return r(),s(w,{ref:"form","label-width":"80px",size:"large"},{default:t(()=>[l(U,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>[l(d,{label:"页面标题"},{default:t(()=>[l(f,{modelValue:a(o).title_type,"onUpdate:modelValue":e[0]||(e[0]=n=>a(o).title_type=n)},{default:t(()=>[l(u,{value:"1"},{default:t(()=>[...e[7]||(e[7]=[p("文字",-1)])]),_:1}),l(u,{value:"2"},{default:t(()=>[...e[8]||(e[8]=[p("图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),m.content.title_type==1?(r(),s(d,{key:0},{default:t(()=>[l(k,{modelValue:a(o).title,"onUpdate:modelValue":e[1]||(e[1]=n=>a(o).title=n),maxlength:"8","show-word-limit":"",class:"w-[300px]",placeholder:"请输入页面标题"},null,8,["modelValue"])]),_:1})):i("",!0),m.content.title_type==2?(r(),s(d,{key:1},{default:t(()=>[l(V,{modelValue:a(o).title_img,"onUpdate:modelValue":e[2]||(e[2]=n=>a(o).title_img=n),limit:1,size:"100px"},null,8,["modelValue"]),e[9]||(e[9]=y("div",{class:"form-tips"},"建议图片尺寸:300px*40px",-1))]),_:1})):i("",!0),m.content.title_type==1?(r(),s(d,{key:2,label:"文字颜色"},{default:t(()=>[l(f,{modelValue:a(o).text_color,"onUpdate:modelValue":e[3]||(e[3]=n=>a(o).text_color=n)},{default:t(()=>[l(u,{value:"1"},{default:t(()=>[...e[10]||(e[10]=[p("白色",-1)])]),_:1}),l(u,{value:"2"},{default:t(()=>[...e[11]||(e[11]=[p("黑色",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1})):i("",!0),l(d,{label:"页面背景"},{default:t(()=>[l(f,{modelValue:a(o).bg_type,"onUpdate:modelValue":e[4]||(e[4]=n=>a(o).bg_type=n)},{default:t(()=>[l(u,{value:"1"},{default:t(()=>[...e[12]||(e[12]=[p("背景颜色",-1)])]),_:1}),l(u,{value:"2"},{default:t(()=>[...e[13]||(e[13]=[p("背景图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),m.content.bg_type==1?(r(),s(d,{key:3},{default:t(()=>[l(v,{modelValue:a(o).bg_color,"onUpdate:modelValue":e[5]||(e[5]=n=>a(o).bg_color=n),"reset-color":"#F5F5F5"},null,8,["modelValue"])]),_:1})):i("",!0),m.content.bg_type==2?(r(),s(d,{key:4},{default:t(()=>[l(V,{modelValue:a(o).bg_image,"onUpdate:modelValue":e[6]||(e[6]=n=>a(o).bg_image=n),limit:1,size:"100px"},null,8,["modelValue"]),e[14]||(e[14]=y("div",{class:"form-tips"},"建议图片尺寸:750px*高度不限",-1))]),_:1})):i("",!0)]),_:1})]),_:1},512)}}});export{T as _};
@@ -1 +1 @@
import{J as I,B as O,C as j,g as A,i as F,D as J}from"./element-plus-DFTWCWyi.js";import{_ as z}from"./index-BeKT8md7.js";import{c as G,i as g}from"./index-D2tYw7RM.js";import{_ as H}from"./picker-N14js34s.js";import{_ as R}from"./picker-DxFyzHJw.js";import{D as S}from"./vuedraggable-5bKFmC7X.js";import{k as v}from"./lodash-es-C2A-Pj28.js";import{f as T,ak as _,I as h,a as t,aN as a,J as s,G as q,O as K,H as L,A as M}from"./@vue/runtime-core-C6bnekPw.js";import{y as p}from"./@vue/reactivity-DiY1c2vO.js";const P={class:"bg-fill-light flex items-center w-full p-4 mt-4"},Q={class:"ml-3 flex-1"},W={class:"flex-1 flex items-center"},X={class:"drag-move cursor-move ml-auto"},Y={key:0,class:"mt-4"},r=5,ce=T({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(u,{emit:k}){const d=k,m=u,f=M({get:()=>m.content,set:l=>{d("update:content",l)}}),b=()=>{var l;if(((l=m.content.data)==null?void 0:l.length)<r){const e=v(m.content);e.data.push({is_show:"1",image:"",name:"",link:{}}),d("update:content",e)}else g.msgError(`最多添加${r}张图片`)},w=l=>{var c;if(((c=m.content.data)==null?void 0:c.length)<=1)return g.msgError("最少保留一张图片");const e=v(m.content);e.data.splice(l,1),d("update:content",e)};return(l,e)=>{const c=R,y=j,i=O,E=H,U=A,C=G,B=z,D=F,N=I,$=J;return _(),h("div",null,[t($,{"label-width":"70px"},{default:a(()=>[t(N,{shadow:"never",class:"!border-none flex mt-2"},{default:a(()=>{var x;return[e[2]||(e[2]=s("div",{class:"flex items-end mb-4"},[s("div",{class:"text-base text-[#101010] font-medium"},"菜单"),s("div",{class:"text-xs text-tx-secondary ml-2"}," 最多添加5张,建议图片尺寸:750px*200px ")],-1)),t(p(S),{class:"draggable",modelValue:p(f).data,"onUpdate:modelValue":e[0]||(e[0]=o=>p(f).data=o),animation:"300",handle:".drag-move","item-key":"index"},{item:a(({element:o,index:V})=>[(_(),q(B,{key:V,onClose:n=>w(V),class:"w-[467px]"},{default:a(()=>[s("div",P,[t(c,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body","exclude-domain":""},null,8,["modelValue","onUpdate:modelValue"]),s("div",Q,[t(i,{label:"图片名称"},{default:a(()=>[t(y,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(i,{class:"mt-[18px]",label:"图片链接"},{default:a(()=>[t(E,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(i,{label:"是否显示",class:"mt-[18px]"},{default:a(()=>[s("div",W,[t(U,{modelValue:o.is_show,"onUpdate:modelValue":n=>o.is_show=n,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),s("div",X,[t(C,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])])]),_:2},1032,["onClose"]))]),_:1},8,["modelValue"]),((x=u.content.data)==null?void 0:x.length)<r?(_(),h("div",Y,[t(D,{class:"w-full",type:"primary",onClick:b},{default:a(()=>[...e[1]||(e[1]=[K("添加图片",-1)])]),_:1})])):L("",!0)]}),_:1})]),_:1})])}}});export{ce as _};
import{J as I,B as O,C as j,g as A,i as F,D as J}from"./element-plus-DFTWCWyi.js";import{_ as z}from"./index-B1yDaEur.js";import{c as G,i as g}from"./index-KChY3YtM.js";import{_ as H}from"./picker-BV8NrMs7.js";import{_ as R}from"./picker-DBkge4jE.js";import{D as S}from"./vuedraggable-5bKFmC7X.js";import{k as v}from"./lodash-es-C2A-Pj28.js";import{f as T,ak as _,I as h,a as t,aN as a,J as s,G as q,O as K,H as L,A as M}from"./@vue/runtime-core-C6bnekPw.js";import{y as p}from"./@vue/reactivity-DiY1c2vO.js";const P={class:"bg-fill-light flex items-center w-full p-4 mt-4"},Q={class:"ml-3 flex-1"},W={class:"flex-1 flex items-center"},X={class:"drag-move cursor-move ml-auto"},Y={key:0,class:"mt-4"},r=5,ce=T({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(u,{emit:k}){const d=k,m=u,f=M({get:()=>m.content,set:l=>{d("update:content",l)}}),b=()=>{var l;if(((l=m.content.data)==null?void 0:l.length)<r){const e=v(m.content);e.data.push({is_show:"1",image:"",name:"",link:{}}),d("update:content",e)}else g.msgError(`最多添加${r}张图片`)},w=l=>{var c;if(((c=m.content.data)==null?void 0:c.length)<=1)return g.msgError("最少保留一张图片");const e=v(m.content);e.data.splice(l,1),d("update:content",e)};return(l,e)=>{const c=R,y=j,i=O,E=H,U=A,C=G,B=z,D=F,N=I,$=J;return _(),h("div",null,[t($,{"label-width":"70px"},{default:a(()=>[t(N,{shadow:"never",class:"!border-none flex mt-2"},{default:a(()=>{var x;return[e[2]||(e[2]=s("div",{class:"flex items-end mb-4"},[s("div",{class:"text-base text-[#101010] font-medium"},"菜单"),s("div",{class:"text-xs text-tx-secondary ml-2"}," 最多添加5张,建议图片尺寸:750px*200px ")],-1)),t(p(S),{class:"draggable",modelValue:p(f).data,"onUpdate:modelValue":e[0]||(e[0]=o=>p(f).data=o),animation:"300",handle:".drag-move","item-key":"index"},{item:a(({element:o,index:V})=>[(_(),q(B,{key:V,onClose:n=>w(V),class:"w-[467px]"},{default:a(()=>[s("div",P,[t(c,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body","exclude-domain":""},null,8,["modelValue","onUpdate:modelValue"]),s("div",Q,[t(i,{label:"图片名称"},{default:a(()=>[t(y,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(i,{class:"mt-[18px]",label:"图片链接"},{default:a(()=>[t(E,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(i,{label:"是否显示",class:"mt-[18px]"},{default:a(()=>[s("div",W,[t(U,{modelValue:o.is_show,"onUpdate:modelValue":n=>o.is_show=n,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),s("div",X,[t(C,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])])]),_:2},1032,["onClose"]))]),_:1},8,["modelValue"]),((x=u.content.data)==null?void 0:x.length)<r?(_(),h("div",Y,[t(D,{class:"w-full",type:"primary",onClick:b},{default:a(()=>[...e[1]||(e[1]=[K("添加图片",-1)])]),_:1})])):L("",!0)]}),_:1})]),_:1})])}}});export{ce as _};
@@ -1 +1 @@
import{J as j,B as A,C as F,g as J,i as S,D as z}from"./element-plus-DFTWCWyi.js";import{_ as G}from"./index-BeKT8md7.js";import{c as H,i as k}from"./index-D2tYw7RM.js";import{_ as R}from"./picker-N14js34s.js";import{_ as T}from"./picker-DxFyzHJw.js";import{D as q}from"./vuedraggable-5bKFmC7X.js";import{k as v}from"./lodash-es-C2A-Pj28.js";import{f as K,ak as d,I as b,a as o,aN as s,J as n,G as u,H as r,O as L,A as M}from"./@vue/runtime-core-C6bnekPw.js";import{y as _}from"./@vue/reactivity-DiY1c2vO.js";const P={class:"flex-1"},Q={class:"bg-fill-light w-full p-4 mt-4"},W={class:"flex-1"},X={class:"flex-1 flex items-center"},Y={class:"drag-move cursor-move ml-auto"},Z={key:0,class:"mt-4"},f=5,me=K({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(m,{emit:y}){const p=y,c=m,g=M({get:()=>c.content,set:a=>{p("update:content",a)}}),w=()=>{var a;if(((a=c.content.data)==null?void 0:a.length)<f){const e=v(c.content);e.data.push({is_show:"1",image:"",name:"",link:{}}),p("update:content",e)}else k.msgError(`最多添加${f}张图片`)},E=a=>{var i;if(((i=c.content.data)==null?void 0:i.length)<=1)return k.msgError("最少保留一张图片");const e=v(c.content);e.data.splice(a,1),p("update:content",e)};return(a,e)=>{const i=T,U=R,C=F,h=A,B=J,D=H,N=G,$=S,I=j,O=z;return d(),b("div",null,[o(O,{"label-width":"70px"},{default:s(()=>[o(I,{shadow:"never",class:"!border-none flex mt-2"},{default:s(()=>{var x;return[e[2]||(e[2]=n("div",{class:"flex items-end"},[n("div",{class:"text-base text-[#101010] font-medium"},"图片设置"),n("div",{class:"text-xs text-tx-secondary ml-2"}," 最多添加5张,建议图片尺寸:750px*200px ")],-1)),n("div",P,[o(_(q),{class:"draggable",modelValue:_(g).data,"onUpdate:modelValue":e[0]||(e[0]=t=>_(g).data=t),animation:"300",handle:".drag-move"},{item:s(({element:t,index:V})=>[(d(),u(N,{key:V,onClose:l=>E(V),class:"w-full"},{default:s(()=>[n("div",Q,[o(i,{width:"396px",height:"196px",modelValue:t.image,"onUpdate:modelValue":l=>t.image=l,"upload-class":"bg-body","exclude-domain":""},null,8,["modelValue","onUpdate:modelValue"]),n("div",W,[o(h,{class:"mt-[18px]",label:"图片链接"},{default:s(()=>[m.type=="mobile"?(d(),u(U,{key:0,modelValue:t.link,"onUpdate:modelValue":l=>t.link=l},null,8,["modelValue","onUpdate:modelValue"])):r("",!0),m.type=="pc"?(d(),u(C,{key:1,placeholder:"请输入链接",modelValue:t.link.path,"onUpdate:modelValue":l=>t.link.path=l},null,8,["modelValue","onUpdate:modelValue"])):r("",!0)]),_:2},1024),o(h,{label:"是否显示",class:"mt-[18px] !mb-0"},{default:s(()=>[n("div",X,[o(B,{modelValue:t.is_show,"onUpdate:modelValue":l=>t.is_show=l,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),n("div",Y,[o(D,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])])]),_:2},1032,["onClose"]))]),_:1},8,["modelValue"])]),((x=m.content.data)==null?void 0:x.length)<f?(d(),b("div",Z,[o($,{class:"w-full",type:"primary",onClick:w},{default:s(()=>[...e[1]||(e[1]=[L("添加图片",-1)])]),_:1})])):r("",!0)]}),_:1})]),_:1})])}}});export{me as _};
import{J as j,B as A,C as F,g as J,i as S,D as z}from"./element-plus-DFTWCWyi.js";import{_ as G}from"./index-B1yDaEur.js";import{c as H,i as k}from"./index-KChY3YtM.js";import{_ as R}from"./picker-BV8NrMs7.js";import{_ as T}from"./picker-DBkge4jE.js";import{D as q}from"./vuedraggable-5bKFmC7X.js";import{k as v}from"./lodash-es-C2A-Pj28.js";import{f as K,ak as d,I as b,a as o,aN as s,J as n,G as u,H as r,O as L,A as M}from"./@vue/runtime-core-C6bnekPw.js";import{y as _}from"./@vue/reactivity-DiY1c2vO.js";const P={class:"flex-1"},Q={class:"bg-fill-light w-full p-4 mt-4"},W={class:"flex-1"},X={class:"flex-1 flex items-center"},Y={class:"drag-move cursor-move ml-auto"},Z={key:0,class:"mt-4"},f=5,me=K({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(m,{emit:y}){const p=y,c=m,g=M({get:()=>c.content,set:a=>{p("update:content",a)}}),w=()=>{var a;if(((a=c.content.data)==null?void 0:a.length)<f){const e=v(c.content);e.data.push({is_show:"1",image:"",name:"",link:{}}),p("update:content",e)}else k.msgError(`最多添加${f}张图片`)},E=a=>{var i;if(((i=c.content.data)==null?void 0:i.length)<=1)return k.msgError("最少保留一张图片");const e=v(c.content);e.data.splice(a,1),p("update:content",e)};return(a,e)=>{const i=T,U=R,C=F,h=A,B=J,D=H,N=G,$=S,I=j,O=z;return d(),b("div",null,[o(O,{"label-width":"70px"},{default:s(()=>[o(I,{shadow:"never",class:"!border-none flex mt-2"},{default:s(()=>{var x;return[e[2]||(e[2]=n("div",{class:"flex items-end"},[n("div",{class:"text-base text-[#101010] font-medium"},"图片设置"),n("div",{class:"text-xs text-tx-secondary ml-2"}," 最多添加5张,建议图片尺寸:750px*200px ")],-1)),n("div",P,[o(_(q),{class:"draggable",modelValue:_(g).data,"onUpdate:modelValue":e[0]||(e[0]=t=>_(g).data=t),animation:"300",handle:".drag-move"},{item:s(({element:t,index:V})=>[(d(),u(N,{key:V,onClose:l=>E(V),class:"w-full"},{default:s(()=>[n("div",Q,[o(i,{width:"396px",height:"196px",modelValue:t.image,"onUpdate:modelValue":l=>t.image=l,"upload-class":"bg-body","exclude-domain":""},null,8,["modelValue","onUpdate:modelValue"]),n("div",W,[o(h,{class:"mt-[18px]",label:"图片链接"},{default:s(()=>[m.type=="mobile"?(d(),u(U,{key:0,modelValue:t.link,"onUpdate:modelValue":l=>t.link=l},null,8,["modelValue","onUpdate:modelValue"])):r("",!0),m.type=="pc"?(d(),u(C,{key:1,placeholder:"请输入链接",modelValue:t.link.path,"onUpdate:modelValue":l=>t.link.path=l},null,8,["modelValue","onUpdate:modelValue"])):r("",!0)]),_:2},1024),o(h,{label:"是否显示",class:"mt-[18px] !mb-0"},{default:s(()=>[n("div",X,[o(B,{modelValue:t.is_show,"onUpdate:modelValue":l=>t.is_show=l,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),n("div",Y,[o(D,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])])]),_:2},1032,["onClose"]))]),_:1},8,["modelValue"])]),((x=m.content.data)==null?void 0:x.length)<f?(d(),b("div",Z,[o($,{class:"w-full",type:"primary",onClick:w},{default:s(()=>[...e[1]||(e[1]=[L("添加图片",-1)])]),_:1})])):r("",!0)]}),_:1})]),_:1})])}}});export{me as _};
@@ -1 +1 @@
import{J as b,B as y,C as E,G as w,I as B,D as C}from"./element-plus-DFTWCWyi.js";import{_ as I}from"./add-nav.vue_vue_type_script_setup_true_lang-WWde2pX5.js";import{f as N,ak as k,I as O,a as t,aN as o,J as a,O as u,A as U}from"./@vue/runtime-core-C6bnekPw.js";import{y as s}from"./@vue/reactivity-DiY1c2vO.js";const g={class:"flex-1"},J=N({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(p,{emit:i}){const f=i,_=p,l=U({get:()=>_.content,set:m=>{f("update:content",m)}});return(m,e)=>{const x=E,c=y,d=b,r=B,v=w,V=C;return k(),O("div",null,[t(V,{"label-width":"70px"},{default:o(()=>[t(d,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[t(c,{label:"标题"},{default:o(()=>[t(x,{class:"w-[396px]",modelValue:s(l).title,"onUpdate:modelValue":e[0]||(e[0]=n=>s(l).title=n)},null,8,["modelValue"])]),_:1})]),_:1}),t(d,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[5]||(e[5]=a("div",{class:"flex items-end mb-4"},[a("div",{class:"text-base text-[#101010] font-medium"},"展示样式")],-1)),t(v,{modelValue:s(l).style,"onUpdate:modelValue":e[1]||(e[1]=n=>s(l).style=n)},{default:o(()=>[t(r,{value:1},{default:o(()=>[...e[3]||(e[3]=[u("横排",-1)])]),_:1}),t(r,{value:2},{default:o(()=>[...e[4]||(e[4]=[u("竖排",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),t(d,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[6]||(e[6]=a("div",{class:"flex items-end mb-4"},[a("div",{class:"text-base text-[#101010] font-medium"},"菜单"),a("div",{class:"text-xs text-tx-secondary ml-2"},"建议图片尺寸:100px*100px")],-1)),a("div",g,[t(I,{modelValue:s(l).data,"onUpdate:modelValue":e[2]||(e[2]=n=>s(l).data=n)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{J as _};
import{J as b,B as y,C as E,G as w,I as B,D as C}from"./element-plus-DFTWCWyi.js";import{_ as I}from"./add-nav.vue_vue_type_script_setup_true_lang-O5VeJfV0.js";import{f as N,ak as k,I as O,a as t,aN as o,J as a,O as u,A as U}from"./@vue/runtime-core-C6bnekPw.js";import{y as s}from"./@vue/reactivity-DiY1c2vO.js";const g={class:"flex-1"},J=N({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(p,{emit:i}){const f=i,_=p,l=U({get:()=>_.content,set:m=>{f("update:content",m)}});return(m,e)=>{const x=E,c=y,d=b,r=B,v=w,V=C;return k(),O("div",null,[t(V,{"label-width":"70px"},{default:o(()=>[t(d,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[t(c,{label:"标题"},{default:o(()=>[t(x,{class:"w-[396px]",modelValue:s(l).title,"onUpdate:modelValue":e[0]||(e[0]=n=>s(l).title=n)},null,8,["modelValue"])]),_:1})]),_:1}),t(d,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[5]||(e[5]=a("div",{class:"flex items-end mb-4"},[a("div",{class:"text-base text-[#101010] font-medium"},"展示样式")],-1)),t(v,{modelValue:s(l).style,"onUpdate:modelValue":e[1]||(e[1]=n=>s(l).style=n)},{default:o(()=>[t(r,{value:1},{default:o(()=>[...e[3]||(e[3]=[u("横排",-1)])]),_:1}),t(r,{value:2},{default:o(()=>[...e[4]||(e[4]=[u("竖排",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),t(d,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[6]||(e[6]=a("div",{class:"flex items-end mb-4"},[a("div",{class:"text-base text-[#101010] font-medium"},"菜单"),a("div",{class:"text-xs text-tx-secondary ml-2"},"建议图片尺寸:100px*100px")],-1)),a("div",g,[t(I,{modelValue:s(l).data,"onUpdate:modelValue":e[2]||(e[2]=n=>s(l).data=n)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{J as _};
@@ -1 +1 @@
import{J as B,G as F,I as N,B as O,P as U,Q as g,D as C}from"./element-plus-DFTWCWyi.js";import{_ as I}from"./add-nav.vue_vue_type_script_setup_true_lang-WWde2pX5.js";import{f as j,ak as d,I as m,a as l,aN as o,J as s,O as x,F as c,ap as v,A as D}from"./@vue/runtime-core-C6bnekPw.js";import{y as n}from"./@vue/reactivity-DiY1c2vO.js";const G={class:"flex-1 mt-4"},P=j({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(V,{emit:b}){const y=b,w=V,a=D({get:()=>w.content,set:u=>{y("update:content",u)}});return(u,e)=>{const r=N,E=F,p=g,i=U,_=O,f=B,k=C;return d(),m("div",null,[l(k,{"label-width":"70px"},{default:o(()=>[l(f,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[6]||(e[6]=s("div",{class:"flex items-end mb-4"},[s("div",{class:"text-base text-[#101010] font-medium"},"展示样式")],-1)),l(E,{modelValue:n(a).style,"onUpdate:modelValue":e[0]||(e[0]=t=>n(a).style=t)},{default:o(()=>[l(r,{value:1},{default:o(()=>[...e[4]||(e[4]=[x("固定显示",-1)])]),_:1}),l(r,{value:2},{default:o(()=>[...e[5]||(e[5]=[x("分页滑动",-1)])]),_:1})]),_:1},8,["modelValue"]),l(_,{label:"每行数量",class:"mt-4"},{default:o(()=>[l(i,{modelValue:n(a).per_line,"onUpdate:modelValue":e[1]||(e[1]=t=>n(a).per_line=t),style:{width:"300px"}},{default:o(()=>[(d(),m(c,null,v(5,t=>l(p,{key:t,label:t+"个",value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"])]),_:1}),l(_,{label:"显示行数"},{default:o(()=>[l(i,{modelValue:n(a).show_line,"onUpdate:modelValue":e[2]||(e[2]=t=>n(a).show_line=t),style:{width:"300px"}},{default:o(()=>[(d(),m(c,null,v(2,t=>l(p,{key:t,label:t+"行",value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"])]),_:1})]),_:1}),l(f,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[7]||(e[7]=s("div",{class:"flex items-end"},[s("div",{class:"text-base text-[#101010] font-medium"},"菜单设置"),s("div",{class:"text-xs text-tx-secondary ml-2"},"建议图片尺寸:100px*100px")],-1)),s("div",G,[l(I,{modelValue:n(a).data,"onUpdate:modelValue":e[3]||(e[3]=t=>n(a).data=t)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{P as _};
import{J as B,G as F,I as N,B as O,P as U,Q as g,D as C}from"./element-plus-DFTWCWyi.js";import{_ as I}from"./add-nav.vue_vue_type_script_setup_true_lang-O5VeJfV0.js";import{f as j,ak as d,I as m,a as l,aN as o,J as s,O as x,F as c,ap as v,A as D}from"./@vue/runtime-core-C6bnekPw.js";import{y as n}from"./@vue/reactivity-DiY1c2vO.js";const G={class:"flex-1 mt-4"},P=j({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(V,{emit:b}){const y=b,w=V,a=D({get:()=>w.content,set:u=>{y("update:content",u)}});return(u,e)=>{const r=N,E=F,p=g,i=U,_=O,f=B,k=C;return d(),m("div",null,[l(k,{"label-width":"70px"},{default:o(()=>[l(f,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[6]||(e[6]=s("div",{class:"flex items-end mb-4"},[s("div",{class:"text-base text-[#101010] font-medium"},"展示样式")],-1)),l(E,{modelValue:n(a).style,"onUpdate:modelValue":e[0]||(e[0]=t=>n(a).style=t)},{default:o(()=>[l(r,{value:1},{default:o(()=>[...e[4]||(e[4]=[x("固定显示",-1)])]),_:1}),l(r,{value:2},{default:o(()=>[...e[5]||(e[5]=[x("分页滑动",-1)])]),_:1})]),_:1},8,["modelValue"]),l(_,{label:"每行数量",class:"mt-4"},{default:o(()=>[l(i,{modelValue:n(a).per_line,"onUpdate:modelValue":e[1]||(e[1]=t=>n(a).per_line=t),style:{width:"300px"}},{default:o(()=>[(d(),m(c,null,v(5,t=>l(p,{key:t,label:t+"个",value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"])]),_:1}),l(_,{label:"显示行数"},{default:o(()=>[l(i,{modelValue:n(a).show_line,"onUpdate:modelValue":e[2]||(e[2]=t=>n(a).show_line=t),style:{width:"300px"}},{default:o(()=>[(d(),m(c,null,v(2,t=>l(p,{key:t,label:t+"行",value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"])]),_:1})]),_:1}),l(f,{shadow:"never",class:"!border-none flex mt-2"},{default:o(()=>[e[7]||(e[7]=s("div",{class:"flex items-end"},[s("div",{class:"text-base text-[#101010] font-medium"},"菜单设置"),s("div",{class:"text-xs text-tx-secondary ml-2"},"建议图片尺寸:100px*100px")],-1)),s("div",G,[l(I,{modelValue:n(a).data,"onUpdate:modelValue":e[3]||(e[3]=t=>n(a).data=t)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{P as _};
@@ -1 +1 @@
import{_ as o}from"./auth.vue_vue_type_script_setup_true_lang-ONaLDUS7.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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"./menu-C6whT3q5.js";import"./index-D2tYw7RM.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"./role-Ix0yf1GP.js";import"./index-CKd1YhbK.js";export{o as default};
import{_ as o}from"./auth.vue_vue_type_script_setup_true_lang-fPSSOoil.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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"./menu-DCitFRVu.js";import"./index-KChY3YtM.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"./role-DHO9whHE.js";import"./index-C0sC4Td0.js";export{o as default};
@@ -1 +1 @@
import{D as I,s as G,B as J,H as M,Z as O,L as P}from"./element-plus-DFTWCWyi.js";import{m as U}from"./menu-C6whT3q5.js";import{a as Z}from"./role-Ix0yf1GP.js";import{_ as j}from"./index-CKd1YhbK.js";import{x as z}from"./index-D2tYw7RM.js";import{f as Q,ak as k,I as W,a as l,aN as d,aP as X,G as Y,J as y,n as x}from"./@vue/runtime-core-C6bnekPw.js";import{y as c,a as $,q as f,n as r,r as ee}from"./@vue/reactivity-DiY1c2vO.js";const te={class:"edit-popup"},de=Q({__name:"auth",emits:["success","close"],setup(ae,{expose:C,emit:g}){const _=g,o=f(),h=f(),u=f(),b=r(!1),i=r(!0),m=r(!1),v=r([]),p=r([]),s=ee({id:"",name:"",desc:"",sort:0,data_scope:1,menu_id:[]}),E={name:[{required:!0,message:"请输入名称",trigger:["blur"]}]},w=()=>{m.value=!0,U().then(e=>{p.value=e,v.value=z(e),x(()=>{A()}),m.value=!1})},R=()=>{var a,n;const e=(a=o.value)==null?void 0:a.getCheckedKeys(),t=(n=o.value)==null?void 0:n.getHalfCheckedKeys();return e==null||e.unshift.apply(e,t),e},A=()=>{s.menu_id.forEach(e=>{x(()=>{var t;(t=o.value)==null||t.setChecked(e,!0,!1)})})},D=e=>{const t=p.value;for(let a=0;a<t.length;a++)o.value.store.nodesMap[t[a].id].expanded=e},K=e=>{var t,a;e?(t=o.value)==null||t.setCheckedKeys(v.value.map(n=>n.id)):(a=o.value)==null||a.setCheckedKeys([])},B=async()=>{var e,t;await((e=h.value)==null?void 0:e.validate()),s.menu_id=R(),await Z(s),(t=u.value)==null||t.close(),_("success")},V=()=>{_("close")},S=()=>{var e;(e=u.value)==null||e.open()},T=async e=>{for(const t in s)e[t]!=null&&e[t]!=null&&(s[t]=e[t])};return w(),C({open:S,setFormData:T}),(e,t)=>{const a=M,n=O,F=J,L=G,N=I,q=P;return k(),W("div",te,[l(j,{ref_key:"popupRef",ref:u,title:"分配权限",async:!0,width:"550px",onConfirm:B,onClose:V},{default:d(()=>[X((k(),Y(N,{class:"ls-form",ref_key:"formRef",ref:h,rules:E,model:c(s),"label-width":"60px"},{default:d(()=>[l(L,{class:"h-[400px] sm:h-[600px]"},{default:d(()=>[l(F,{label:"权限",prop:"menu_id"},{default:d(()=>[y("div",null,[l(a,{label:"展开/折叠",onChange:D}),l(a,{label:"全选/不全选",onChange:K}),l(a,{modelValue:c(i),"onUpdate:modelValue":t[0]||(t[0]=H=>$(i)?i.value=H:null),label:"父子联动"},null,8,["modelValue"]),y("div",null,[l(n,{ref_key:"treeRef",ref:o,data:c(p),props:{label:"name",children:"children"},"check-strictly":!c(i),"node-key":"id","default-expand-all":c(b),"show-checkbox":""},null,8,["data","check-strictly","default-expand-all"])])])]),_:1})]),_:1})]),_:1},8,["model"])),[[q,c(m)]])]),_:1},512)])}}});export{de as _};
import{D as I,s as G,B as J,H as M,Z as O,L as P}from"./element-plus-DFTWCWyi.js";import{m as U}from"./menu-DCitFRVu.js";import{a as Z}from"./role-DHO9whHE.js";import{_ as j}from"./index-C0sC4Td0.js";import{x as z}from"./index-KChY3YtM.js";import{f as Q,ak as k,I as W,a as l,aN as d,aP as X,G as Y,J as y,n as x}from"./@vue/runtime-core-C6bnekPw.js";import{y as c,a as $,q as f,n as r,r as ee}from"./@vue/reactivity-DiY1c2vO.js";const te={class:"edit-popup"},de=Q({__name:"auth",emits:["success","close"],setup(ae,{expose:C,emit:g}){const _=g,o=f(),h=f(),u=f(),b=r(!1),i=r(!0),m=r(!1),v=r([]),p=r([]),s=ee({id:"",name:"",desc:"",sort:0,data_scope:1,menu_id:[]}),E={name:[{required:!0,message:"请输入名称",trigger:["blur"]}]},w=()=>{m.value=!0,U().then(e=>{p.value=e,v.value=z(e),x(()=>{A()}),m.value=!1})},R=()=>{var a,n;const e=(a=o.value)==null?void 0:a.getCheckedKeys(),t=(n=o.value)==null?void 0:n.getHalfCheckedKeys();return e==null||e.unshift.apply(e,t),e},A=()=>{s.menu_id.forEach(e=>{x(()=>{var t;(t=o.value)==null||t.setChecked(e,!0,!1)})})},D=e=>{const t=p.value;for(let a=0;a<t.length;a++)o.value.store.nodesMap[t[a].id].expanded=e},K=e=>{var t,a;e?(t=o.value)==null||t.setCheckedKeys(v.value.map(n=>n.id)):(a=o.value)==null||a.setCheckedKeys([])},B=async()=>{var e,t;await((e=h.value)==null?void 0:e.validate()),s.menu_id=R(),await Z(s),(t=u.value)==null||t.close(),_("success")},V=()=>{_("close")},S=()=>{var e;(e=u.value)==null||e.open()},T=async e=>{for(const t in s)e[t]!=null&&e[t]!=null&&(s[t]=e[t])};return w(),C({open:S,setFormData:T}),(e,t)=>{const a=M,n=O,F=J,L=G,N=I,q=P;return k(),W("div",te,[l(j,{ref_key:"popupRef",ref:u,title:"分配权限",async:!0,width:"550px",onConfirm:B,onClose:V},{default:d(()=>[X((k(),Y(N,{class:"ls-form",ref_key:"formRef",ref:h,rules:E,model:c(s),"label-width":"60px"},{default:d(()=>[l(L,{class:"h-[400px] sm:h-[600px]"},{default:d(()=>[l(F,{label:"权限",prop:"menu_id"},{default:d(()=>[y("div",null,[l(a,{label:"展开/折叠",onChange:D}),l(a,{label:"全选/不全选",onChange:K}),l(a,{modelValue:c(i),"onUpdate:modelValue":t[0]||(t[0]=H=>$(i)?i.value=H:null),label:"父子联动"},null,8,["modelValue"]),y("div",null,[l(n,{ref_key:"treeRef",ref:o,data:c(p),props:{label:"name",children:"children"},"check-strictly":!c(i),"node-key":"id","default-expand-all":c(b),"show-checkbox":""},null,8,["data","check-strictly","default-expand-all"])])])]),_:1})]),_:1})]),_:1},8,["model"])),[[q,c(m)]])]),_:1},512)])}}});export{de as _};
@@ -1 +1 @@
import{K as L,D as N,B as K,C as I,P as O,Q as z,i as J,J as Q,M as R,N as S,L as $}from"./element-plus-DFTWCWyi.js";import{_ as j}from"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import{h as q}from"./index-D2tYw7RM.js";import{_ as A}from"./index.vue_vue_type_script_setup_true_lang-DPC_NOWM.js";import{w as G}from"./@vue/runtime-dom-DDAG46FW.js";import{g as M,h as H}from"./finance-DHn55Bu-.js";import{u as W}from"./useDictOptions-BH-W6eP4.js";import{u as X}from"./usePaging-VsbTxSU0.js";import{f as v,ak as s,I as h,a as e,aN as n,F as Y,ap as Z,G as w,O as p,aP as ee,J as _}from"./@vue/runtime-core-C6bnekPw.js";import{y as o,a as te,r as oe}from"./@vue/reactivity-DiY1c2vO.js";import{Q as y,o as ae}from"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-HOEUG8sr.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"./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 ne={class:"flex items-center"},le={class:"flex justify-end mt-4"},ie=v({name:"balanceDetail"}),Xe=v({...ie,setup(re){const l=oe({user_info:"",change_type:"",start_time:"",end_time:""}),{pager:r,getLists:d,resetPage:c,resetParams:C}=X({fetchFun:M,params:l}),{optionsData:x}=W({change_type:{api:H}});return d(),(me,a)=>{const V=L,E=I,m=K,u=z,T=O,k=A,f=J,B=N,g=Q,i=S,D=q,P=R,U=j,F=$;return s(),h("div",null,[e(g,{class:"!border-none",shadow:"never"},{default:n(()=>[e(V,{type:"warning",title:"温馨提示:用户账户变动记录",closable:!1,"show-icon":""}),e(B,{ref:"formRef",class:"mb-[-16px] mt-[16px]",model:o(l),inline:!0},{default:n(()=>[e(m,{class:"w-[280px]",label:"用户信息"},{default:n(()=>[e(E,{modelValue:o(l).user_info,"onUpdate:modelValue":a[0]||(a[0]=t=>o(l).user_info=t),placeholder:"请输入用户账号/昵称/手机号",clearable:"",onKeyup:G(o(c),["enter"])},null,8,["modelValue","onKeyup"])]),_:1}),e(m,{class:"w-[280px]",label:"变动类型"},{default:n(()=>[e(T,{modelValue:o(l).change_type,"onUpdate:modelValue":a[1]||(a[1]=t=>o(l).change_type=t)},{default:n(()=>[e(u,{label:"全部",value:""}),(s(!0),h(Y,null,Z(o(x).change_type,(t,b)=>(s(),w(u,{key:b,label:t,value:b},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),_:1}),e(m,{label:"记录时间"},{default:n(()=>[e(k,{startTime:o(l).start_time,"onUpdate:startTime":a[2]||(a[2]=t=>o(l).start_time=t),endTime:o(l).end_time,"onUpdate:endTime":a[3]||(a[3]=t=>o(l).end_time=t)},null,8,["startTime","endTime"])]),_:1}),e(m,null,{default:n(()=>[e(f,{type:"primary",onClick:o(c)},{default:n(()=>[...a[5]||(a[5]=[p("查询",-1)])]),_:1},8,["onClick"]),e(f,{onClick:o(C)},{default:n(()=>[...a[6]||(a[6]=[p("重置",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["model"])]),_:1}),e(g,{class:"!border-none mt-4",shadow:"never"},{default:n(()=>[ee((s(),w(P,{size:"large",data:o(r).lists},{default:n(()=>[e(i,{label:"用户账号",prop:"account","min-width":"100"}),e(i,{label:"用户昵称","min-width":"160"},{default:n(({row:t})=>[_("div",ne,[e(D,{class:"flex-none mr-2",src:t.avatar,width:40,height:40,"preview-teleported":"",fit:"contain"},null,8,["src"]),p(" "+y(t.nickname),1)])]),_:1}),e(i,{label:"手机号码",prop:"mobile","min-width":"100"}),e(i,{label:"变动金额",prop:"change_amount","min-width":"100"},{default:n(({row:t})=>[_("span",{class:ae({"text-error":t.action==2})},y(t.change_amount),3)]),_:1}),e(i,{label:"剩余金额",prop:"left_amount","min-width":"100"}),e(i,{label:"变动类型",prop:"change_type_desc","min-width":"120"}),e(i,{label:"来源单号",prop:"source_sn","min-width":"100"}),e(i,{label:"记录时间",prop:"create_time","min-width":"120"})]),_:1},8,["data"])),[[F,o(r).loading]]),_("div",le,[e(U,{modelValue:o(r),"onUpdate:modelValue":a[4]||(a[4]=t=>te(r)?r.value=t:null),onChange:o(d)},null,8,["modelValue","onChange"])])]),_:1})])}}});export{Xe as default};
import{K as L,D as N,B as K,C as I,P as O,Q as z,i as J,J as Q,M as R,N as S,L as $}from"./element-plus-DFTWCWyi.js";import{_ as j}from"./index.vue_vue_type_script_setup_true_lang-CcvIuIWy.js";import{h as q}from"./index-KChY3YtM.js";import{_ as A}from"./index.vue_vue_type_script_setup_true_lang-DPC_NOWM.js";import{w as G}from"./@vue/runtime-dom-DDAG46FW.js";import{g as M,h as H}from"./finance-DqAxj1JL.js";import{u as W}from"./useDictOptions-cAwi1RWT.js";import{u as X}from"./usePaging-VsbTxSU0.js";import{f as v,ak as s,I as h,a as e,aN as n,F as Y,ap as Z,G as w,O as p,aP as ee,J as _}from"./@vue/runtime-core-C6bnekPw.js";import{y as o,a as te,r as oe}from"./@vue/reactivity-DiY1c2vO.js";import{Q as y,o as ae}from"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-HOEUG8sr.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"./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 ne={class:"flex items-center"},le={class:"flex justify-end mt-4"},ie=v({name:"balanceDetail"}),Xe=v({...ie,setup(re){const l=oe({user_info:"",change_type:"",start_time:"",end_time:""}),{pager:r,getLists:d,resetPage:c,resetParams:C}=X({fetchFun:M,params:l}),{optionsData:x}=W({change_type:{api:H}});return d(),(me,a)=>{const V=L,E=I,m=K,u=z,T=O,k=A,f=J,B=N,g=Q,i=S,D=q,P=R,U=j,F=$;return s(),h("div",null,[e(g,{class:"!border-none",shadow:"never"},{default:n(()=>[e(V,{type:"warning",title:"温馨提示:用户账户变动记录",closable:!1,"show-icon":""}),e(B,{ref:"formRef",class:"mb-[-16px] mt-[16px]",model:o(l),inline:!0},{default:n(()=>[e(m,{class:"w-[280px]",label:"用户信息"},{default:n(()=>[e(E,{modelValue:o(l).user_info,"onUpdate:modelValue":a[0]||(a[0]=t=>o(l).user_info=t),placeholder:"请输入用户账号/昵称/手机号",clearable:"",onKeyup:G(o(c),["enter"])},null,8,["modelValue","onKeyup"])]),_:1}),e(m,{class:"w-[280px]",label:"变动类型"},{default:n(()=>[e(T,{modelValue:o(l).change_type,"onUpdate:modelValue":a[1]||(a[1]=t=>o(l).change_type=t)},{default:n(()=>[e(u,{label:"全部",value:""}),(s(!0),h(Y,null,Z(o(x).change_type,(t,b)=>(s(),w(u,{key:b,label:t,value:b},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),_:1}),e(m,{label:"记录时间"},{default:n(()=>[e(k,{startTime:o(l).start_time,"onUpdate:startTime":a[2]||(a[2]=t=>o(l).start_time=t),endTime:o(l).end_time,"onUpdate:endTime":a[3]||(a[3]=t=>o(l).end_time=t)},null,8,["startTime","endTime"])]),_:1}),e(m,null,{default:n(()=>[e(f,{type:"primary",onClick:o(c)},{default:n(()=>[...a[5]||(a[5]=[p("查询",-1)])]),_:1},8,["onClick"]),e(f,{onClick:o(C)},{default:n(()=>[...a[6]||(a[6]=[p("重置",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["model"])]),_:1}),e(g,{class:"!border-none mt-4",shadow:"never"},{default:n(()=>[ee((s(),w(P,{size:"large",data:o(r).lists},{default:n(()=>[e(i,{label:"用户账号",prop:"account","min-width":"100"}),e(i,{label:"用户昵称","min-width":"160"},{default:n(({row:t})=>[_("div",ne,[e(D,{class:"flex-none mr-2",src:t.avatar,width:40,height:40,"preview-teleported":"",fit:"contain"},null,8,["src"]),p(" "+y(t.nickname),1)])]),_:1}),e(i,{label:"手机号码",prop:"mobile","min-width":"100"}),e(i,{label:"变动金额",prop:"change_amount","min-width":"100"},{default:n(({row:t})=>[_("span",{class:ae({"text-error":t.action==2})},y(t.change_amount),3)]),_:1}),e(i,{label:"剩余金额",prop:"left_amount","min-width":"100"}),e(i,{label:"变动类型",prop:"change_type_desc","min-width":"120"}),e(i,{label:"来源单号",prop:"source_sn","min-width":"100"}),e(i,{label:"记录时间",prop:"create_time","min-width":"120"})]),_:1},8,["data"])),[[F,o(r).loading]]),_("div",le,[e(U,{modelValue:o(r),"onUpdate:modelValue":a[4]||(a[4]=t=>te(r)?r.value=t:null),onChange:o(d)},null,8,["modelValue","onChange"])])]),_:1})])}}});export{Xe as default};
@@ -1 +1 @@
import{K as c,J as _,M as d,N as f,i as u}from"./element-plus-DFTWCWyi.js";import{i as h,B as b}from"./index-D2tYw7RM.js";import{f as i,ak as w,I as C,a as t,aN as o,O as k}from"./@vue/runtime-core-C6bnekPw.js";import{y,n as E}from"./@vue/reactivity-DiY1c2vO.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-HOEUG8sr.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 x={class:"cache"},B=i({name:"cache"}),st=i({...B,setup(N){const m=E([{content:"系统缓存",desc:"系统运行过程中产生的各类缓存数据"}]),n=async()=>{await h.confirm("确认清除系统缓存?"),await b(),window.location.reload()};return(g,r)=>{const p=c,a=_,e=f,l=u,s=d;return w(),C("div",x,[t(a,{class:"!border-none",shadow:"never"},{default:o(()=>[t(p,{type:"warning",title:"温馨提示:管理系统运行过程中产生的缓存",closable:!1,"show-icon":""})]),_:1}),t(a,{class:"!border-none mt-4",shadow:"never"},{default:o(()=>[t(s,{data:y(m),size:"large"},{default:o(()=>[t(e,{label:"管理内容",prop:"content","min-width":"130"}),t(e,{label:"内容说明",prop:"desc","min-width":"180"}),t(e,{label:"操作",width:"130",fixed:"right"},{default:o(()=>[t(l,{type:"primary",link:"",onClick:n},{default:o(()=>[...r[0]||(r[0]=[k("清除系统缓存",-1)])]),_:1})]),_:1})]),_:1},8,["data"])]),_:1})])}}});export{st as default};
import{K as c,J as _,M as d,N as f,i as u}from"./element-plus-DFTWCWyi.js";import{i as h,B as b}from"./index-KChY3YtM.js";import{f as i,ak as w,I as C,a as t,aN as o,O as k}from"./@vue/runtime-core-C6bnekPw.js";import{y,n as E}from"./@vue/reactivity-DiY1c2vO.js";import"./@vue/runtime-dom-DDAG46FW.js";import"./lodash-D3kF6u-c.js";import"./@vue/shared-mAAVTE9n.js";import"./@element-plus/icons-vue-HOEUG8sr.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 x={class:"cache"},B=i({name:"cache"}),st=i({...B,setup(N){const m=E([{content:"系统缓存",desc:"系统运行过程中产生的各类缓存数据"}]),n=async()=>{await h.confirm("确认清除系统缓存?"),await b(),window.location.reload()};return(g,r)=>{const p=c,a=_,e=f,l=u,s=d;return w(),C("div",x,[t(a,{class:"!border-none",shadow:"never"},{default:o(()=>[t(p,{type:"warning",title:"温馨提示:管理系统运行过程中产生的缓存",closable:!1,"show-icon":""})]),_:1}),t(a,{class:"!border-none mt-4",shadow:"never"},{default:o(()=>[t(s,{data:y(m),size:"large"},{default:o(()=>[t(e,{label:"管理内容",prop:"content","min-width":"130"}),t(e,{label:"内容说明",prop:"desc","min-width":"180"}),t(e,{label:"操作",width:"130",fixed:"right"},{default:o(()=>[t(l,{type:"primary",link:"",onClick:n},{default:o(()=>[...r[0]||(r[0]=[k("清除系统缓存",-1)])]),_:1})]),_:1})]),_:1},8,["data"])]),_:1})])}}});export{st as default};
@@ -1 +1 @@
import{E as p,B as b,C as v,D as E,i as h}from"./element-plus-DFTWCWyi.js";import{u as V,g as C,P,c as B,d as F,_ as I}from"./index-D2tYw7RM.js";import{w as L}from"./@vue/runtime-dom-DDAG46FW.js";import{u as N}from"./useLockFn-X4Qce5KO.js";import{_ as z}from"./footer.vue_vue_type_script_setup_true_lang-CDPNwOoy.js";import{a as R}from"./vue-router-QlpZ4wdW.js";import{f as S,b as q,ak as U,I as D,J as i,a as s,aN as t,O as K}from"./@vue/runtime-core-C6bnekPw.js";import{y as u,q as M,r as O}from"./@vue/reactivity-DiY1c2vO.js";import"./@vue/shared-mAAVTE9n.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-HOEUG8sr.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"./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 T={class:"change-password flex flex-col"},$={class:"flex-1 flex items-center justify-center"},j={class:"change-password-card bg-body rounded-md px-10 py-10 w-[480px]"},G=S({__name:"change-password",setup(J){const n=M(),_=R(),d=V();q(()=>{C()||(p.error("请先登录"),_.push(P.LOGIN))});const e=O({password:"",password_confirm:""}),w={password:[{required:!0,message:"请输入新密码",trigger:"blur"},{min:6,message:"密码长度不能少于6位",trigger:"blur"}],password_confirm:[{required:!0,validator:(a,o,r)=>{o===""?r(new Error("请再次输入密码")):o!==e.password?r(new Error("两次输入的密码不一致")):r()},trigger:"blur"}]},l=async()=>{var a;await((a=n.value)==null?void 0:a.validate());try{await F({password:e.password,password_confirm:e.password_confirm}),p.success("密码修改成功,请重新登录"),d.isPaw=1,await d.logout()}catch(o){p.error((o==null?void 0:o.msg)||(o==null?void 0:o.message)||"密码修改失败")}},{isLock:g,lockFn:x}=N(l);return(a,o)=>{const r=B,c=v,f=b,y=E,k=h;return U(),D("div",T,[i("div",$,[i("div",j,[o[3]||(o[3]=i("div",{class:"text-center text-2xl font-medium mb-2"},"首次登录",-1)),o[4]||(o[4]=i("div",{class:"text-center text-gray-500 text-sm mb-8"},"为了您的账号安全,请修改初始密码",-1)),s(y,{ref_key:"formRef",ref:n,model:e,size:"large",rules:w},{default:t(()=>[s(f,{prop:"password"},{default:t(()=>[s(c,{modelValue:e.password,"onUpdate:modelValue":o[0]||(o[0]=m=>e.password=m),type:"password","show-password":"",placeholder:"请输入新密码"},{prepend:t(()=>[s(r,{name:"el-icon-Lock",size:"16"})]),_:1},8,["modelValue"])]),_:1}),s(f,{prop:"password_confirm"},{default:t(()=>[s(c,{modelValue:e.password_confirm,"onUpdate:modelValue":o[1]||(o[1]=m=>e.password_confirm=m),type:"password","show-password":"",placeholder:"请再次输入新密码",onKeyup:L(l,["enter"])},{prepend:t(()=>[s(r,{name:"el-icon-Lock",size:"16"})]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["model"]),s(k,{type:"primary",size:"large",loading:u(g),onClick:u(x),class:"w-full"},{default:t(()=>[...o[2]||(o[2]=[K(" 确认修改 ",-1)])]),_:1},8,["loading","onClick"])])]),s(z)])}}}),Ro=I(G,[["__scopeId","data-v-bbd4ab41"]]);export{Ro as default};
import{E as p,B as b,C as v,D as E,i as h}from"./element-plus-DFTWCWyi.js";import{u as V,g as C,P,c as B,d as F,_ as I}from"./index-KChY3YtM.js";import{w as L}from"./@vue/runtime-dom-DDAG46FW.js";import{u as N}from"./useLockFn-X4Qce5KO.js";import{_ as z}from"./footer.vue_vue_type_script_setup_true_lang-BqYMM5-L.js";import{a as R}from"./vue-router-QlpZ4wdW.js";import{f as S,b as q,ak as U,I as D,J as i,a as s,aN as t,O as K}from"./@vue/runtime-core-C6bnekPw.js";import{y as u,q as M,r as O}from"./@vue/reactivity-DiY1c2vO.js";import"./@vue/shared-mAAVTE9n.js";import"./lodash-D3kF6u-c.js";import"./@element-plus/icons-vue-HOEUG8sr.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"./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 T={class:"change-password flex flex-col"},$={class:"flex-1 flex items-center justify-center"},j={class:"change-password-card bg-body rounded-md px-10 py-10 w-[480px]"},G=S({__name:"change-password",setup(J){const n=M(),_=R(),d=V();q(()=>{C()||(p.error("请先登录"),_.push(P.LOGIN))});const e=O({password:"",password_confirm:""}),w={password:[{required:!0,message:"请输入新密码",trigger:"blur"},{min:6,message:"密码长度不能少于6位",trigger:"blur"}],password_confirm:[{required:!0,validator:(a,o,r)=>{o===""?r(new Error("请再次输入密码")):o!==e.password?r(new Error("两次输入的密码不一致")):r()},trigger:"blur"}]},l=async()=>{var a;await((a=n.value)==null?void 0:a.validate());try{await F({password:e.password,password_confirm:e.password_confirm}),p.success("密码修改成功,请重新登录"),d.isPaw=1,await d.logout()}catch(o){p.error((o==null?void 0:o.msg)||(o==null?void 0:o.message)||"密码修改失败")}},{isLock:g,lockFn:x}=N(l);return(a,o)=>{const r=B,c=v,f=b,y=E,k=h;return U(),D("div",T,[i("div",$,[i("div",j,[o[3]||(o[3]=i("div",{class:"text-center text-2xl font-medium mb-2"},"首次登录",-1)),o[4]||(o[4]=i("div",{class:"text-center text-gray-500 text-sm mb-8"},"为了您的账号安全,请修改初始密码",-1)),s(y,{ref_key:"formRef",ref:n,model:e,size:"large",rules:w},{default:t(()=>[s(f,{prop:"password"},{default:t(()=>[s(c,{modelValue:e.password,"onUpdate:modelValue":o[0]||(o[0]=m=>e.password=m),type:"password","show-password":"",placeholder:"请输入新密码"},{prepend:t(()=>[s(r,{name:"el-icon-Lock",size:"16"})]),_:1},8,["modelValue"])]),_:1}),s(f,{prop:"password_confirm"},{default:t(()=>[s(c,{modelValue:e.password_confirm,"onUpdate:modelValue":o[1]||(o[1]=m=>e.password_confirm=m),type:"password","show-password":"",placeholder:"请再次输入新密码",onKeyup:L(l,["enter"])},{prepend:t(()=>[s(r,{name:"el-icon-Lock",size:"16"})]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["model"]),s(k,{type:"primary",size:"large",loading:u(g),onClick:u(x),class:"w-full"},{default:t(()=>[...o[2]||(o[2]=[K(" 确认修改 ",-1)])]),_:1},8,["loading","onClick"])])]),s(z)])}}}),Ro=I(G,[["__scopeId","data-v-bbd4ab41"]]);export{Ro as default};
@@ -1 +1 @@
import{r as t}from"./index-D2tYw7RM.js";function o(e){return t.get({url:"/tools.generator/generateTable",params:e})}function n(e){return t.get({url:"/tools.generator/dataTable",params:e})}function a(e){return t.post({url:"/tools.generator/selectTable",params:e})}function l(e){return t.get({url:"/tools.generator/detail",params:e})}function s(e){return t.post({url:"/tools.generator/syncColumn",params:e})}function u(e){return t.post({url:"/tools.generator/delete",params:e})}function g(e){return t.post({url:"/tools.generator/edit",params:e})}function i(e){return t.post({url:"/tools.generator/preview",params:e})}function c(e){return t.post({url:"/tools.generator/generate",params:e})}function f(){return t.get({url:"/tools.generator/getModels"})}export{f as a,o as b,u as c,i as d,c as e,n as f,g,a as h,s,l as t};
import{r as t}from"./index-KChY3YtM.js";function o(e){return t.get({url:"/tools.generator/generateTable",params:e})}function n(e){return t.get({url:"/tools.generator/dataTable",params:e})}function a(e){return t.post({url:"/tools.generator/selectTable",params:e})}function l(e){return t.get({url:"/tools.generator/detail",params:e})}function s(e){return t.post({url:"/tools.generator/syncColumn",params:e})}function u(e){return t.post({url:"/tools.generator/delete",params:e})}function g(e){return t.post({url:"/tools.generator/edit",params:e})}function i(e){return t.post({url:"/tools.generator/preview",params:e})}function c(e){return t.post({url:"/tools.generator/generate",params:e})}function f(){return t.get({url:"/tools.generator/getModels"})}export{f as a,o as b,u as c,i as d,c as e,n as f,g,a as h,s,l as t};
@@ -1 +1 @@
import{_ as o}from"./code-preview.vue_vue_type_script_setup_true_lang-D3bOw1eb.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-D2tYw7RM.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};
import{_ as o}from"./code-preview.vue_vue_type_script_setup_true_lang-8S9IDX4X.js";import"./element-plus-DFTWCWyi.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-HOEUG8sr.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-KChY3YtM.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};
@@ -1 +1 @@
import{m as B,l as N,s as T,i as $,V as j}from"./element-plus-DFTWCWyi.js";import{c as D,i as d}from"./index-D2tYw7RM.js";import{u as F}from"./vue-clipboard3-DByT_rEQ.js";import{f as S,ar as U,ak as c,I as i,a as t,aN as a,F as A,ap as G,G as I,J as u,O as J,A as L}from"./@vue/runtime-core-C6bnekPw.js";import{a as p,y as _,n as O}from"./@vue/reactivity-DiY1c2vO.js";const P={class:"code-preview"},R={class:"flex",style:{height:"50vh"}},W=S({__name:"code-preview",props:{modelValue:{type:Boolean},code:{}},emits:["update:modelValue"],setup(r,{emit:f}){const V=r,b=f,{toClipboard:g}=F(),n=O("index0"),h=async l=>{try{await g(l),d.msgSuccess("复制成功")}catch{d.msgError("复制失败")}},s=L({get(){return V.modelValue},set(l){b("update:modelValue",l)}});return(l,e)=>{const v=U("highlightjs"),y=T,k=D,C=$,x=N,E=B,w=j;return c(),i("div",P,[t(w,{modelValue:_(s),"onUpdate:modelValue":e[1]||(e[1]=o=>p(s)?s.value=o:null),width:"900px",title:"代码预览"},{default:a(()=>[t(E,{modelValue:_(n),"onUpdate:modelValue":e[0]||(e[0]=o=>p(n)?n.value=o:null)},{default:a(()=>[(c(!0),i(A,null,G(r.code,(o,m)=>(c(),I(x,{label:o.name,name:`index${m}`,key:m},{default:a(()=>[u("div",R,[t(y,{class:"flex-1"},{default:a(()=>[t(v,{autodetect:"",code:o.content},null,8,["code"])]),_:2},1024),u("div",null,[t(C,{onClick:q=>h(o.content),type:"primary",link:""},{icon:a(()=>[t(k,{name:"el-icon-CopyDocument"})]),default:a(()=>[e[2]||(e[2]=J(" 复制 ",-1))]),_:1},8,["onClick"])])])]),_:2},1032,["label","name"]))),128))]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])])}}});export{W as _};
import{m as B,l as N,s as T,i as $,V as j}from"./element-plus-DFTWCWyi.js";import{c as D,i as d}from"./index-KChY3YtM.js";import{u as F}from"./vue-clipboard3-DByT_rEQ.js";import{f as S,ar as U,ak as c,I as i,a as t,aN as a,F as A,ap as G,G as I,J as u,O as J,A as L}from"./@vue/runtime-core-C6bnekPw.js";import{a as p,y as _,n as O}from"./@vue/reactivity-DiY1c2vO.js";const P={class:"code-preview"},R={class:"flex",style:{height:"50vh"}},W=S({__name:"code-preview",props:{modelValue:{type:Boolean},code:{}},emits:["update:modelValue"],setup(r,{emit:f}){const V=r,b=f,{toClipboard:g}=F(),n=O("index0"),h=async l=>{try{await g(l),d.msgSuccess("复制成功")}catch{d.msgError("复制失败")}},s=L({get(){return V.modelValue},set(l){b("update:modelValue",l)}});return(l,e)=>{const v=U("highlightjs"),y=T,k=D,C=$,x=N,E=B,w=j;return c(),i("div",P,[t(w,{modelValue:_(s),"onUpdate:modelValue":e[1]||(e[1]=o=>p(s)?s.value=o:null),width:"900px",title:"代码预览"},{default:a(()=>[t(E,{modelValue:_(n),"onUpdate:modelValue":e[0]||(e[0]=o=>p(n)?n.value=o:null)},{default:a(()=>[(c(!0),i(A,null,G(r.code,(o,m)=>(c(),I(x,{label:o.name,name:`index${m}`,key:m},{default:a(()=>[u("div",R,[t(y,{class:"flex-1"},{default:a(()=>[t(v,{autodetect:"",code:o.content},null,8,["code"])]),_:2},1024),u("div",null,[t(C,{onClick:q=>h(o.content),type:"primary",link:""},{icon:a(()=>[t(k,{name:"el-icon-CopyDocument"})]),default:a(()=>[e[2]||(e[2]=J(" 复制 ",-1))]),_:1},8,["onClick"])])])]),_:2},1032,["label","name"]))),128))]),_:1},8,["modelValue"])]),_:1},8,["modelValue"])])}}});export{W as _};
File diff suppressed because one or more lines are too long

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