Compare commits

...
4 Commits
Author SHA1 Message Date
Your Name af1db59c07 更新 2026-08-25 09:41:26 +08:00
Your Name 47094cc617 更新 2026-08-25 09:36:25 +08:00
Your Name 01c38d8c5b 更新 2026-08-25 09:35:47 +08:00
Your Name 1f3e580cf8 更新 2026-08-25 09:34:39 +08:00
363 changed files with 2298 additions and 770 deletions
+14 -6
View File
@@ -190,9 +190,9 @@ export function wecomPromotionOverview() {
return request.get({ url: '/firstvisit.wecomPromotion/overview' })
}
export function wecomPromotionSavePool(params: Record<string, unknown>) {
return request.post({ url: '/firstvisit.wecomPromotion/savePool', params })
}
export function wecomPromotionSavePool(params: Record<string, unknown>) {
return request.post({ url: '/firstvisit.wecomPromotion/savePool', params, timeout: 120000 })
}
export function wecomPromotionSaveWidget(params: Record<string, unknown>) {
return request.post({ url: '/firstvisit.wecomPromotion/saveWidget', params })
@@ -202,9 +202,17 @@ export function wecomPromotionDeletePool(params: { id: number }) {
return request.post({ url: '/firstvisit.wecomPromotion/deletePool', params })
}
export function wecomPromotionSaveLink(params: Record<string, unknown>) {
return request.post({ url: '/firstvisit.wecomPromotion/saveLink', params })
}
export function wecomPromotionSaveLink(params: Record<string, unknown>) {
return request.post({ url: '/firstvisit.wecomPromotion/saveLink', params })
}
export function wecomPromotionSaveMember(params: Record<string, unknown>) {
return request.post({ url: '/firstvisit.wecomPromotion/saveMember', params, timeout: 120000 })
}
export function wecomPromotionToggleMember(params: { id: number; status: number }) {
return request.post({ url: '/firstvisit.wecomPromotion/toggleMember', params, timeout: 120000 })
}
export function wecomPromotionCheckApiPermission() {
return request.post({ url: '/firstvisit.wecomPromotion/checkApiPermission' })
@@ -239,7 +239,7 @@
<div class="install-tip">
<el-icon><CircleCheck /></el-icon>
<span><strong>无需暴露链接</strong>浮窗点击后仍由服务端执行可用性筛选权重随机和访问统计</span>
<span><strong>一个方案一个官方链接</strong>浮窗会直接打开企业微信链接多名医助由企业微信执行均衡分流</span>
</div>
</section>
</section>
@@ -274,6 +274,8 @@ interface PromotionPool {
name?: string
public_key?: string
script_url?: string
main_url?: string
compat_go_url?: string
go_url?: string
install_code?: string
trigger_code?: string
@@ -437,11 +439,12 @@ async function copySnippet(value: string | undefined, label: string) {
}
function openTestLink() {
if (!props.pool.go_url) {
const targetUrl = props.pool.main_url || props.pool.go_url || props.pool.compat_go_url
if (!targetUrl) {
ElMessage.warning('当前方案暂无测试链接')
return
}
window.open(props.pool.go_url, '_blank', 'noopener,noreferrer')
window.open(targetUrl, '_blank', 'noopener,noreferrer')
}
</script>
@@ -5,7 +5,7 @@
<span class="heading-icon"><el-icon><Promotion /></el-icon></span>
<div>
<h1>企业微信获客助手</h1>
<p>对接企业微信获客助手官方 API按角色与部门管理获客成员并将链接安全分流到推广页面</p>
<p>一个方案保留一条企业微信官方直链按回调结果自动调度医助权重与数量</p>
</div>
</div>
<div class="heading-actions">
@@ -22,15 +22,15 @@
</article>
<article class="metric-card">
<span class="metric-icon is-blue"><el-icon><SetUp /></el-icon></span>
<div><small>分流方案</small><strong>{{ overview.summary.pool_count }}</strong><p>每个方案生成独立 JS</p></div>
<div><small>分流方案</small><strong>{{ overview.summary.pool_count }}</strong><p>每个方案对应一个官方链接</p></div>
</article>
<article class="metric-card">
<span class="metric-icon is-green"><el-icon><Link /></el-icon></span>
<div><small>在线链接</small><strong>{{ overview.summary.online_links }}</strong><p>停用或超限自动排除</p></div>
<div><small>官方链接</small><strong>{{ overview.summary.online_links }}</strong><p>链接不变成员范围自动切换</p></div>
</article>
<article class="metric-card">
<span class="metric-icon is-orange"><el-icon><Mouse /></el-icon></span>
<div><small>今日分流点击</small><strong>{{ overview.summary.today_clicks }}</strong><p>只记录脱敏访问数据</p></div>
<div><small>今日实际获客</small><strong>{{ overview.summary.today_clicks }}</strong><p>按企业微信回调确认承接成员</p></div>
</article>
</section>
@@ -52,9 +52,9 @@
<div v-if="activeTab === 'links'" class="tab-content links-tab">
<div class="section-heading">
<div>
<h2>获客助手链接分流</h2>
<p>访客点击时由服务端从当前可用的获客助手链接中按权重随机选择页面端不会暴露完整链接</p>
<div>
<h2>获客助手分流方案</h2>
<p>选择几名医助就生成几条成员规则官方链接只在方案顶部复制成员行不重复展示链接</p>
</div>
<el-button type="primary" :icon="Plus" @click="openPoolDialog()">新建分流方案</el-button>
</div>
@@ -69,7 +69,7 @@
@click="selectedPoolId = Number(pool.id)"
>
<span class="pool-status" :class="Number(pool.status) === 1 ? 'online' : 'offline'" />
<span><strong>{{ pool.name }}</strong><small>{{ linkCount(pool.id) }} 条链接 · {{ formatNumber(pool.click_count) }} 次点击</small></span>
<span><strong>{{ pool.name }}</strong><small>{{ memberSummary(pool) }} · {{ pool.main_url ? '官方链接已生成' : '待生成链接' }}</small></span>
<el-icon><ArrowRight /></el-icon>
</button>
</aside>
@@ -84,100 +84,77 @@
</span>
<span class="owner-tag">{{ selectedPool.dept_name || '未分部门' }} · {{ selectedPool.owner_name || '系统' }}</span>
</div>
<p>公开键{{ selectedPool.public_key }}</p>
</div>
<div class="toolbar-actions">
<el-button :icon="CircleCheck" :loading="checkingApi" @click="checkApiPermission">验证 API</el-button>
<el-button :icon="Refresh" :loading="syncingRemote" @click="syncRemoteLinks">同步企业微信</el-button>
<el-button :icon="DocumentCopy" @click="copyText(selectedPool.install_code, 'JS 安装代码')">复制 JS</el-button>
<el-button :icon="Edit" @click="openPoolDialog(selectedPool)">编辑方案</el-button>
<el-button type="danger" plain :icon="Delete" @click="removePool(selectedPool)">删除</el-button>
<el-button type="primary" :icon="Plus" @click="openLinkDialog()">创建官方获客链接</el-button>
</div>
</div>
<el-alert
v-if="selectedLegacyCount > 0 && selectedOfficialCount === 0"
class="legacy-sync-alert"
type="warning"
show-icon
:closable="false"
:title="`当前方案的 ${selectedLegacyCount} 条链接都是历史手工链接,企业微信同步不会返回它们`"
description="官方接口只返回当前应用通过 API 创建的获客链接。现有链接仍可参与本地分流;如需同步 link_id、客户和官方统计,请点击“创建官方获客链接”。"
/>
<el-table :data="selectedLinks" class="link-table" stripe>
<el-table-column label="推广成员 / 分组" min-width="180" fixed="left">
<template #default="{ row }">
<div class="member-cell"><strong>{{ row.name }}</strong><small>{{ row.group_name || '默认分组' }}</small></div>
</template>
</el-table-column>
<el-table-column label="企业微信链接 ID" min-width="280">
<template #default="{ row }">
<div class="link-id-cell">
<span v-if="row.remote_link_id" class="remote-id" :title="row.remote_link_id">{{ row.remote_link_id }}</span>
<span v-else class="legacy-tag">历史手工链接</span>
<a
v-if="row.wecom_url"
class="wecom-url"
:href="row.wecom_url"
:title="row.wecom_url"
target="_blank"
rel="noopener noreferrer"
@click.stop
>{{ row.wecom_url }}</a>
<el-button
v-if="row.wecom_url"
type="primary"
link
class="copy-url-btn"
@click.stop="copyText(row.wecom_url, '企业微信链接')"
>复制链接</el-button>
<span v-else class="muted">暂无链接地址</span>
</div>
</template>
</el-table-column>
<el-table-column label="可用成员" min-width="150">
<template #default="{ row }">
<span>{{ remoteMemberLabel(row) }}</span>
</template>
</el-table-column>
<el-table-column label="权重" prop="weight" width="84" align="center" />
<el-table-column label="今日 / 上限" min-width="120" align="center">
<template #default="{ row }">{{ todayCount(row) }} / {{ Number(row.daily_limit) ? row.daily_limit : '不限' }}</template>
</el-table-column>
<el-table-column label="累计点击" prop="click_count" min-width="105" align="center" />
<el-table-column label="当前可用性" min-width="130">
<template #default="{ row }">
<span class="availability" :class="eligibility(row).className">{{ eligibility(row).label }}</span>
</template>
</el-table-column>
<el-table-column label="上线" width="90" align="center">
<template #default="{ row }">
<el-switch :model-value="Number(row.status) === 1" :disabled="Number(row.remote_status) === 2" @change="(value) => handleToggle(row, value)" />
</template>
</el-table-column>
<el-table-column label="操作" min-width="245" fixed="right">
<template #default="{ row }">
<el-button v-if="row.is_official && Number(row.remote_status) !== 2" type="primary" link :loading="refreshingLinkId === Number(row.id)" @click="refreshRemoteDetail(row)">刷新详情</el-button>
<el-button v-if="!row.is_official || Number(row.remote_status) !== 2" type="primary" link @click="openLinkDialog(row)">编辑</el-button>
<el-dropdown v-if="row.is_official" trigger="click" @command="(command) => handleLinkCommand(command, row)">
<el-button type="primary" link>更多<el-icon class="el-icon--right"><ArrowDown /></el-icon></el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="local">从本地移除</el-dropdown-item>
<el-dropdown-item v-if="Number(row.remote_status) !== 2" command="remote" divided class="danger-command">永久删除企业微信链接</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-button v-else type="danger" link @click="removeLink(row)">从本地移除</el-button>
</template>
</el-table-column>
<template #empty><el-empty :image-size="72" description="当前方案还没有获客助手链接" /></template>
</el-table>
<p>公开键{{ selectedPool.public_key }}</p>
</div>
<div class="toolbar-actions">
<el-button :icon="CircleCheck" :loading="checkingApi" @click="checkApiPermission">验证 API</el-button>
<el-button :icon="DocumentCopy" :disabled="!selectedPool.main_url" @click="copyText(selectedPool.main_url, '官方获客链接')">复制链接</el-button>
<el-button :icon="DocumentCopy" @click="copyText(selectedPool.install_code, 'JS 安装代码')">复制 JS</el-button>
<el-button :icon="Edit" @click="openPoolDialog(selectedPool)">编辑方案</el-button>
<el-button type="danger" plain :icon="Delete" @click="removePool(selectedPool)">删除</el-button>
</div>
</div>
<el-alert
v-if="selectedPool.migration_state === 'needs_resolution'"
class="legacy-sync-alert"
type="warning"
show-icon
:closable="false"
title="检测到旧版方案存在多个官方链接"
description="当前显示最新链接;保存方案后,其余旧链接只会在本地下线,企业微信端与历史客户归因仍会保留。"
/>
<el-alert
class="legacy-sync-alert"
type="info"
show-icon
:closable="false"
title="回调驱动分流"
description="企业微信确认实际承接成员后,系统累计今日数量,并在符合启用状态、有效期和上限的成员中按权重随机抽取下一位;随机结果可能连续命中同一人,并发访问及企微同步存在短暂延迟。"
/>
<el-table :data="selectedMemberRules" class="link-table" stripe>
<el-table-column label="推广成员" min-width="210" fixed="left">
<template #default="{ row }">
<div class="member-cell">
<strong>{{ row.name || row.userid }}</strong>
<small>{{ memberRuleDetail(row) }}</small>
</div>
</template>
</el-table-column>
<el-table-column label="调度" width="105" align="center">
<template #default="{ row }">
<span v-if="row.is_current" class="status-tag is-online">{{ Number(row.sync_status) === 0 ? '当前命中' : '待切换' }}</span>
<span v-else-if="row.is_applied" class="status-tag is-offline">切换中</span>
<span v-else class="muted">候选</span>
</template>
</el-table-column>
<el-table-column label="权重" prop="weight" width="85" align="center" />
<el-table-column label="今日 / 上限" width="125" align="center">
<template #default="{ row }">{{ todayCount(row) }} / {{ Number(row.daily_limit) ? row.daily_limit : '不限' }}</template>
</el-table-column>
<el-table-column label="累计获客" prop="total_count" width="105" align="center" />
<el-table-column label="当前可用性" min-width="130">
<template #default="{ row }">
<span class="availability" :class="eligibility(row).className">{{ eligibility(row).label }}</span>
</template>
</el-table-column>
<el-table-column label="上线" width="90" align="center">
<template #default="{ row }">
<el-switch :model-value="Number(row.enabled) === 1" :loading="togglingMemberId === Number(row.id)" @change="(value) => handleMemberToggle(row, value)" />
</template>
</el-table-column>
<el-table-column label="操作" min-width="100" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="openMemberDialog(row)">编辑规则</el-button>
</template>
</el-table-column>
<template #empty><el-empty :image-size="72" description="编辑方案并选择获客医助" /></template>
</el-table>
</div>
</div>
<el-empty v-else description="创建一个分流方案,再添加企业微信获客助手链接">
<el-empty v-else description="创建方案并选择多个医助,保存后自动生成一个企业微信官方获客链接">
<el-button type="primary" :icon="Plus" @click="openPoolDialog()">创建第一个方案</el-button>
</el-empty>
</div>
@@ -220,7 +197,7 @@
show-icon
:closable="false"
title="消息次数回调尚未配置完成"
description="复用企业微信自建应用现有的“API 接收消息”地址即可,无需新增第二个回调;请确保该地址为 QywxExternalContactCallback/notify,且服务器 Token、AESKey 与企微后台一致。未完成前无法得到精确接收消息次数。"
description="复用企业微信自建应用现有的“API 接收消息”地址即可,无需新增第二个回调;请确保该地址为 /api/qywx/external-contact/notify,且服务器 Token、AESKey 与企微后台一致。未完成前无法自动累计成员获客数量和切换下一位。"
/>
<el-alert
@@ -363,75 +340,89 @@
</div>
</section>
<el-dialog v-model="poolDialogVisible" :title="poolForm.id ? '编辑分流方案' : '新建分流方案'" width="560px" destroy-on-close>
<el-form label-position="top">
<el-form-item label="方案名称" required><el-input v-model="poolForm.name" maxlength="60" show-word-limit placeholder="例如:官网咨询分流" /></el-form-item>
<el-form-item label="兜底获客助手链接">
<el-input v-model="poolForm.fallback_url" placeholder="可选;没有可用成员时跳转" />
<span class="form-tip">仅接受企业微信获客助手生成的 https://work.weixin.qq.com/ca/... 链接。</span>
</el-form-item>
<el-form-item label="运行状态"><el-switch v-model="poolForm.status" :active-value="1" :inactive-value="0" active-text="运行" inactive-text="停用" /></el-form-item>
</el-form>
<template #footer><el-button @click="poolDialogVisible = false">取消</el-button><el-button type="primary" :loading="savingPool" @click="savePool">保存方案</el-button></template>
</el-dialog>
<el-dialog v-model="linkDialogVisible" :title="linkForm.id ? '编辑获客助手链接' : '创建企业微信官方获客链接'" width="720px" destroy-on-close>
<el-form label-position="top" class="link-form">
<div class="form-grid">
<el-form-item label="获客链接名称" required><el-input v-model="linkForm.name" maxlength="80" placeholder="用于企业微信和后台识别" /></el-form-item>
<el-form-item label="分组"><el-input v-model="linkForm.group_name" maxlength="60" placeholder="默认分组" /></el-form-item>
</div>
<el-form-item v-if="!linkForm.legacy" label="获客成员" required>
<el-select v-model="linkForm.member_admin_ids" multiple filterable collapse-tags collapse-tags-tooltip placeholder="仅显示当前角色和部门可管理、且已绑定企业微信的成员" style="width: 100%">
<el-option v-for="member in overview.member_options" :key="member.id" :label="memberOptionLabel(member)" :value="Number(member.id)" />
</el-select>
<span class="form-tip">官方链接按这里的企业微信 userid 建立可见范围越权成员不会出现在列表中</span>
</el-form-item>
<el-form-item v-else label="企业微信获客助手链接" required>
<el-input v-model="linkForm.wecom_url" type="textarea" :rows="2" :placeholder="overview.customer_acquisition_link_example" />
<span class="form-tip">这是历史手工链接只更新本地分流规则不会调用企业微信创建或修改接口</span>
</el-form-item>
<div class="form-grid">
<el-form-item label="分流权重" required><el-input-number v-model="linkForm.weight" :min="1" :max="100" controls-position="right" /></el-form-item>
<el-form-item label="每日点击上限"><el-input-number v-model="linkForm.daily_limit" :min="0" :max="1000000" controls-position="right" /><span class="form-tip">0 表示不限</span></el-form-item>
</div>
<el-form-item v-if="!linkForm.legacy" label="添加客户时跳过验证">
<el-switch v-model="linkForm.skip_verify" :active-value="1" :inactive-value="0" active-text="跳过验证" inactive-text="需要验证" />
</el-form-item>
<el-form-item label="上线状态"><el-switch v-model="linkForm.status" :active-value="1" :inactive-value="0" active-text="上线" inactive-text="下线" /></el-form-item>
<el-form-item label="生效时间段">
<el-date-picker v-model="linkForm.active_range" type="datetimerange" value-format="YYYY-MM-DD HH:mm:ss" start-placeholder="开始时间" end-placeholder="结束时间" range-separator="至" />
<span class="form-tip">不选择表示长期有效</span>
</el-form-item>
<el-form-item label="备注"><el-input v-model="linkForm.remark" maxlength="255" show-word-limit /></el-form-item>
</el-form>
<template #footer><el-button @click="linkDialogVisible = false">取消</el-button><el-button type="primary" :loading="savingLink" @click="saveLink">保存链接</el-button></template>
</el-dialog>
<el-dialog
v-model="poolDialogVisible"
:title="poolForm.id ? '编辑分流方案' : '新建分流方案'"
width="680px"
destroy-on-close
:close-on-click-modal="false"
:close-on-press-escape="!savingPool"
>
<el-form label-position="top">
<el-form-item label="方案名称" required><el-input v-model="poolForm.name" :disabled="savingPool" maxlength="60" show-word-limit placeholder="例如:官网咨询分流" /></el-form-item>
<el-form-item label="获客医助" required>
<el-select
v-model="poolForm.member_admin_ids"
:disabled="savingPool"
multiple
filterable
collapse-tags
collapse-tags-tooltip
placeholder="选择后由企业微信生成一个多人分流链接"
style="width: 100%"
>
<el-option v-for="member in overview.member_options" :key="member.id" :label="memberOptionLabel(member)" :value="Number(member.id)" />
</el-select>
<span class="form-tip">保存后会为每名医助生成一条成员规则官方链接地址始终只有一个</span>
</el-form-item>
<el-form-item label="添加客户时跳过验证">
<el-switch v-model="poolForm.skip_verify" :disabled="savingPool" :active-value="1" :inactive-value="0" active-text="跳过验证" inactive-text="需要验证" />
</el-form-item>
<el-form-item label="兜底获客助手链接">
<el-input v-model="poolForm.fallback_url" :disabled="savingPool" placeholder="可选;仅供旧版兼容跳转使用" />
<span class="form-tip">新生成的官方直链不经过本站跳转此项仅兼容旧安装代码</span>
</el-form-item>
<el-form-item label="运行状态"><el-switch v-model="poolForm.status" :disabled="savingPool" :active-value="1" :inactive-value="0" active-text="运行" inactive-text="停用" /></el-form-item>
</el-form>
<template #footer><el-button :disabled="savingPool" @click="poolDialogVisible = false">取消</el-button><el-button type="primary" :loading="savingPool" @click="savePool">{{ poolForm.id ? '保存方案' : '保存并生成链接' }}</el-button></template>
</el-dialog>
<el-dialog v-model="memberDialogVisible" title="编辑医助分流规则" width="560px" destroy-on-close :close-on-click-modal="false">
<el-form label-position="top">
<el-form-item label="获客医助">
<el-input :model-value="memberForm.name ? `${memberForm.name} · ${memberForm.userid}` : memberForm.userid" readonly />
</el-form-item>
<div class="rule-form-grid">
<el-form-item label="权重" required>
<el-input-number v-model="memberForm.weight" :min="1" :max="100" :disabled="savingMember" style="width: 100%" />
<span class="form-tip">权重越高在后续回调调度中被选中的频率越高</span>
</el-form-item>
<el-form-item label="每日获客上限">
<el-input-number v-model="memberForm.daily_limit" :min="0" :max="1000000" :disabled="savingMember" style="width: 100%" />
<span class="form-tip">0 表示不限数量按实际获客回调累计</span>
</el-form-item>
</div>
<el-form-item label="有效时间">
<el-date-picker v-model="memberForm.active_range" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" :disabled="savingMember" style="width: 100%" />
</el-form-item>
<el-form-item label="上线状态">
<el-switch v-model="memberForm.status" :active-value="1" :inactive-value="0" active-text="启用" inactive-text="禁用" :disabled="savingMember" />
</el-form-item>
<el-form-item label="备注"><el-input v-model="memberForm.remark" type="textarea" :rows="2" maxlength="255" show-word-limit :disabled="savingMember" /></el-form-item>
</el-form>
<template #footer><el-button :disabled="savingMember" @click="memberDialogVisible = false">取消</el-button><el-button type="primary" :loading="savingMember" @click="saveMemberRule">保存规则</el-button></template>
</el-dialog>
</div>
</template>
<script setup lang="ts" name="firstVisitWecomPromotionPage">
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
ArrowDown, ArrowRight, ChatDotRound, CircleCheck, Connection, DataAnalysis, Delete,
DocumentCopy, Edit, Key, Link, Lock, Mouse, OfficeBuilding, Plus,
Promotion, Refresh, Search, SetUp, User, Warning
} from '@element-plus/icons-vue'
import {
wecomPromotionCheckApiPermission,
wecomPromotionCustomerStats,
wecomPromotionDeleteLink,
wecomPromotionDeleteRemoteLink,
wecomPromotionDeletePool,
wecomPromotionOverview,
wecomPromotionRemoteLinkDetail,
wecomPromotionSaveLink,
wecomPromotionSavePool,
wecomPromotionSyncCustomers,
wecomPromotionSyncRemoteLinks,
wecomPromotionToggleLink
} from '@/api/first_visit'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
ArrowRight, ChatDotRound, CircleCheck, Connection, DataAnalysis, Delete,
DocumentCopy, Edit, Key, Link, Lock, Mouse, OfficeBuilding, Plus,
Promotion, Refresh, Search, SetUp, User, Warning
} from '@element-plus/icons-vue'
import {
wecomPromotionCheckApiPermission,
wecomPromotionCustomerStats,
wecomPromotionDeletePool,
wecomPromotionOverview,
wecomPromotionSaveMember,
wecomPromotionSavePool,
wecomPromotionSyncCustomers,
wecomPromotionToggleMember
} from '@/api/first_visit'
import type { WecomPromotionCustomerChatStatus } from '@/api/first_visit'
import WecomFloatingWidgetBuilder from './components/WecomFloatingWidgetBuilder.vue'
@@ -447,17 +438,16 @@ const emptyOverview = () => ({
const overview = reactive(emptyOverview())
const loading = ref(false)
const activeTab = ref<TabName>('links')
const selectedPoolId = ref<number>()
const selectedInstallPoolId = ref<number>()
const poolDialogVisible = ref(false)
const linkDialogVisible = ref(false)
const savingPool = ref(false)
const savingLink = ref(false)
const checkingApi = ref(false)
const syncingRemote = ref(false)
const refreshingLinkId = ref(0)
const poolForm = reactive({ id: 0, name: '', fallback_url: '', status: 1 })
const linkForm = reactive({ id: 0, pool_id: 0, name: '', group_name: '默认分组', wecom_url: '', member_admin_ids: [] as number[], skip_verify: 0, legacy: false, weight: 1, status: 1, daily_limit: 0, active_range: [] as string[], remark: '' })
const selectedPoolId = ref<number>()
const selectedInstallPoolId = ref<number>()
const poolDialogVisible = ref(false)
const savingPool = ref(false)
const checkingApi = ref(false)
const memberDialogVisible = ref(false)
const savingMember = ref(false)
const togglingMemberId = ref(0)
const poolForm = reactive({ id: 0, name: '', fallback_url: '', status: 1, member_admin_ids: [] as number[], skip_verify: 0, main_url: '' })
const memberForm = reactive({ id: 0, name: '', userid: '', weight: 1, daily_limit: 0, status: 1, active_range: [] as string[], remark: '' })
const customerStatsLoading = ref(false)
const customerStatsLoaded = ref(false)
const syncingCustomers = ref(false)
@@ -475,10 +465,8 @@ const customerStats = reactive({
meta: { last_synced_at: '' }
})
const selectedPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedPoolId.value))
const selectedLinks = computed(() => overview.links.filter((item: any) => Number(item.pool_id) === selectedPoolId.value))
const selectedOfficialCount = computed(() => selectedLinks.value.filter((item: any) => Boolean(item.remote_link_id)).length)
const selectedLegacyCount = computed(() => selectedLinks.value.length - selectedOfficialCount.value)
const selectedPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedPoolId.value))
const selectedMemberRules = computed(() => Array.isArray(selectedPool.value?.member_rules) ? selectedPool.value.member_rules : [])
const selectedInstallPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedInstallPoolId.value))
const customerLinkOptions = computed(() => customerStats.link_options.length
? customerStats.link_options
@@ -516,24 +504,37 @@ async function loadOverview() {
}
}
function linkCount(poolId: number) {
return overview.links.filter((item: any) => Number(item.pool_id) === Number(poolId)).length
}
function openPoolDialog(pool?: any) {
Object.assign(poolForm, pool ? { id: Number(pool.id), name: pool.name, fallback_url: pool.fallback_url || '', status: Number(pool.status) } : { id: 0, name: '', fallback_url: '', status: 1 })
poolDialogVisible.value = true
}
async function savePool() {
if (!poolForm.name.trim()) return ElMessage.warning('请输入分流方案名称')
savingPool.value = true
function openPoolDialog(pool?: any) {
Object.assign(poolForm, pool ? {
id: Number(pool.id),
name: pool.name,
fallback_url: pool.fallback_url || '',
status: Number(pool.status),
member_admin_ids: Array.isArray(pool.member_admin_ids) ? pool.member_admin_ids.map(Number) : [],
skip_verify: Number(pool.skip_verify) === 1 ? 1 : 0,
main_url: pool.main_url || ''
} : {
id: 0,
name: '',
fallback_url: '',
status: 1,
member_admin_ids: [],
skip_verify: 0,
main_url: ''
})
poolDialogVisible.value = true
}
async function savePool() {
if (!poolForm.name.trim()) return ElMessage.warning('请输入分流方案名称')
if (!poolForm.member_admin_ids.length) return ElMessage.warning('请至少选择一名获客医助')
savingPool.value = true
try {
const result: any = await wecomPromotionSavePool({ ...poolForm })
poolDialogVisible.value = false
await loadOverview()
if (result?.id) selectedPoolId.value = Number(result.id)
ElMessage.success('分流方案已保存')
ElMessage.success(poolForm.id ? '分流方案已保存' : '分流方案和官方获客链接已创建')
} catch (error: any) {
ElMessage.error(error?.message || '分流方案保存失败')
} finally {
@@ -541,8 +542,8 @@ async function savePool() {
}
}
async function removePool(pool: any) {
await ElMessageBox.confirm(`删除“${pool.name}”后,该方案下的获客助手链接也会停用。确认继续?`, '删除分流方案', { type: 'warning' })
async function removePool(pool: any) {
await ElMessageBox.confirm(`删除“${pool.name}”后,本站将停止使用该链接,但不会永久删除企业微信后台中的官方链接。确认继续?`, '删除分流方案', { type: 'warning' })
try {
await wecomPromotionDeletePool({ id: Number(pool.id) })
ElMessage.success('分流方案已删除')
@@ -550,50 +551,60 @@ async function removePool(pool: any) {
} catch (error: any) {
ElMessage.error(error?.message || '删除失败')
}
}
function openLinkDialog(row?: any) {
if (!selectedPool.value) return
const range = row && Number(row.active_start) > 0 && Number(row.active_end) > 0
? [formatPickerTime(row.active_start), formatPickerTime(row.active_end)] : []
const selectedUserIds = new Set<string>((row?.range_userids || []).map((item: unknown) => String(item)))
const selectedMemberIds = overview.member_options
.filter((member: any) => selectedUserIds.has(String(member.userid)))
.map((member: any) => Number(member.id))
Object.assign(linkForm, row ? {
id: Number(row.id), pool_id: Number(row.pool_id),
name: row.name, group_name: row.group_name || '默认分组', wecom_url: row.wecom_url,
member_admin_ids: selectedMemberIds, skip_verify: Number(row.skip_verify) === 1 ? 1 : 0, legacy: !row.is_official,
weight: Number(row.weight) || 1, status: Number(row.status), daily_limit: Number(row.daily_limit) || 0,
active_range: range, remark: row.remark || ''
} : {
id: 0, pool_id: Number(selectedPool.value.id), name: '', group_name: '默认分组',
wecom_url: '', member_admin_ids: [], skip_verify: 0, legacy: false,
weight: 1, status: 1, daily_limit: 0, active_range: [], remark: ''
})
linkDialogVisible.value = true
}
async function saveLink() {
if (!linkForm.name.trim()) return ElMessage.warning('请输入获客链接名称')
if (linkForm.legacy && !linkForm.wecom_url.trim()) return ElMessage.warning('请填写企业微信获客助手链接')
if (!linkForm.legacy && !linkForm.member_admin_ids.length) return ElMessage.warning('请至少选择一名获客成员')
savingLink.value = true
try {
await wecomPromotionSaveLink({
...linkForm,
active_start: linkForm.active_range?.[0] || '',
active_end: linkForm.active_range?.[1] || ''
})
linkDialogVisible.value = false
await loadOverview()
ElMessage.success(linkForm.legacy ? '本地分流规则已保存' : '企业微信官方获客链接已保存')
} catch (error: any) {
ElMessage.error(error?.message || '获客助手链接保存失败')
} finally {
savingLink.value = false
}
}
}
function openMemberDialog(row: any) {
const range = Number(row.active_start) > 0 && Number(row.active_end) > 0
? [formatPickerTime(row.active_start), formatPickerTime(row.active_end)]
: []
Object.assign(memberForm, {
id: Number(row.id),
name: row.name || '',
userid: row.userid || '',
weight: Number(row.weight) || 1,
daily_limit: Number(row.daily_limit) || 0,
status: Number(row.enabled) === 1 ? 1 : 0,
active_range: range,
remark: row.remark || ''
})
memberDialogVisible.value = true
}
async function saveMemberRule() {
savingMember.value = true
try {
const result: any = await wecomPromotionSaveMember({
...memberForm,
active_start: memberForm.active_range?.[0] || '',
active_end: memberForm.active_range?.[1] || ''
})
memberDialogVisible.value = false
await loadOverview()
result?.sync_error
? ElMessage.warning('规则已保存,企业微信成员范围将在后台自动重试同步')
: ElMessage.success('医助分流规则已保存')
} catch (error: any) {
ElMessage.error(error?.message || '医助分流规则保存失败')
} finally {
savingMember.value = false
}
}
async function handleMemberToggle(row: any, value: unknown) {
togglingMemberId.value = Number(row.id)
try {
const result: any = await wecomPromotionToggleMember({ id: Number(row.id), status: value ? 1 : 0 })
await loadOverview()
result?.sync_error
? ElMessage.warning('成员状态已保存,企业微信成员范围将在后台自动重试同步')
: ElMessage.success(value ? '医助已启用' : '医助已禁用并退出后续调度')
} catch (error: any) {
ElMessage.error(error?.message || '成员状态更新失败')
await loadOverview()
} finally {
togglingMemberId.value = 0
}
}
async function checkApiPermission() {
checkingApi.value = true
@@ -710,119 +721,39 @@ async function syncCustomers() {
}
}
async function syncRemoteLinks() {
if (!selectedPool.value) return ElMessage.warning('请先选择分流方案')
syncingRemote.value = true
try {
const result: any = await wecomPromotionSyncRemoteLinks({ pool_id: Number(selectedPool.value.id) })
const message = `扫描 ${Number(result?.scanned || 0)} 条,新建 ${Number(result?.created || 0)} 条,更新 ${Number(result?.updated || 0)} 条,按权限跳过 ${Number(result?.skipped || 0)} 条,失败 ${Number(result?.failed || 0)}`
if (Number(result?.scanned || 0) === 0) {
await ElMessageBox.alert(
`${result?.empty_reason || '当前应用没有可同步的官方获客链接'}\n\n${result?.suggestion || ''}`,
'没有可同步的官方链接',
{ type: 'warning', confirmButtonText: '知道了' }
)
} else {
result?.failed ? ElMessage.warning(message) : ElMessage.success(message)
}
await loadOverview()
} catch (error: any) {
ElMessage.error(error?.message || '同步企业微信获客链接失败')
} finally {
syncingRemote.value = false
}
}
async function refreshRemoteDetail(row: any) {
refreshingLinkId.value = Number(row.id)
try {
await wecomPromotionRemoteLinkDetail({ id: Number(row.id) })
ElMessage.success('企业微信官方详情已刷新')
await loadOverview()
} catch (error: any) {
ElMessage.error(error?.message || '刷新官方详情失败')
} finally {
refreshingLinkId.value = 0
}
}
async function handleLinkCommand(command: string, row: any) {
if (command === 'local') {
await removeLink(row)
return
}
if (command !== 'remote') return
await ElMessageBox.confirm(
`将永久删除企业微信后台中的“${row.name}”,现有推广页面会立即失效,且无法恢复。确认继续?`,
'永久删除企业微信获客链接',
{ type: 'error', confirmButtonText: '永久删除', cancelButtonText: '取消' }
)
try {
await wecomPromotionDeleteRemoteLink({ id: Number(row.id) })
ElMessage.success('企业微信获客链接已永久删除,本地记录已保留并停止分流')
await loadOverview()
} catch (error: any) {
ElMessage.error(error?.message || '永久删除失败')
}
}
async function handleToggle(row: any, value: unknown) {
try {
await wecomPromotionToggleLink({ id: Number(row.id), status: value ? 1 : 0 })
row.status = value ? 1 : 0
ElMessage.success(value ? '链接已上线' : '链接已下线')
await loadOverview()
} catch (error: any) {
ElMessage.error(error?.message || '状态更新失败')
await loadOverview()
}
}
async function removeLink(row: any) {
await ElMessageBox.confirm(`仅从本地分流池移除“${row.name}”,不会删除企业微信后台的官方链接。确认继续?`, '从本地移除', { type: 'warning' })
try {
await wecomPromotionDeleteLink({ id: Number(row.id) })
ElMessage.success('已从本地分流池移除')
await loadOverview()
} catch (error: any) {
ElMessage.error(error?.message || '删除失败')
}
}
function eligibility(row: any) {
const now = Math.floor(Date.now() / 1000)
if (Number(row.remote_status) === 2) return { label: '企业微信已删除', className: 'is-error' }
if (row.valid_customer_acquisition_link === false) return { label: '非获客助手链接', className: 'is-error' }
if (Number(row.status) !== 1) return { label: '已下线', className: 'is-muted' }
if (Number(row.active_start) > 0 && Number(row.active_start) > now) return { label: '尚未生效', className: 'is-waiting' }
function eligibility(row: any) {
const now = Math.floor(Date.now() / 1000)
if (Number(row.enabled) !== 1) return { label: '已禁用', className: 'is-muted' }
if (Number(row.active_start) > 0 && Number(row.active_start) > now) return { label: '尚未生效', className: 'is-waiting' }
if (Number(row.active_end) > 0 && Number(row.active_end) < now) return { label: '已过期', className: 'is-error' }
if (Number(row.daily_limit) > 0 && todayCount(row) >= Number(row.daily_limit)) return { label: '今日已达上限', className: 'is-waiting' }
return { label: '可参与分流', className: 'is-ok' }
}
if (Number(row.daily_limit) > 0 && todayCount(row) >= Number(row.daily_limit)) return { label: '今日已达上限', className: 'is-waiting' }
const isSyncTarget = Boolean(row.is_current || row.is_applied)
if (isSyncTarget && Number(row.sync_status) === 3) return { label: '企微同步重试中', className: 'is-waiting' }
if (isSyncTarget && Number(row.sync_status) === 4) return { label: '暂无可用调度', className: 'is-error' }
return { label: '可参与分流', className: 'is-ok' }
}
function todayCount(row: any) {
const today = new Intl.DateTimeFormat('en-CA', { timeZone: 'Asia/Shanghai', year: 'numeric', month: '2-digit', day: '2-digit' }).format(new Date())
return row.today_date === today ? Number(row.today_count || 0) : 0
}
function memberOptionLabel(member: any) {
function memberOptionLabel(member: any) {
const departments = Array.isArray(member.dept_names) && member.dept_names.length
? member.dept_names.join(' / ')
: '未分部门'
return `${member.name} · ${departments} · ${member.userid}`
}
return `${member.name} · ${departments} · ${member.userid}`
}
function memberSummary(pool: any) {
const ids = Array.isArray(pool?.member_admin_ids) ? pool.member_admin_ids : []
return ids.length ? `${ids.length} 名医助` : '未选择医助'
}
function remoteMemberLabel(row: any) {
const userIds = Array.isArray(row.range_userids) ? row.range_userids : []
const names = userIds.map((userid: unknown) => {
const member = overview.member_options.find((item: any) => String(item.userid) === String(userid))
return member?.name || String(userid)
})
if (names.length) return names.length > 2 ? `${names.slice(0, 2).join('、')}${names.length}` : names.join('、')
const departments = Array.isArray(row.range_department_ids) ? row.range_department_ids : []
if (departments.length) return `企微部门 ${departments.join('、')}`
return row.is_official ? '未返回成员范围' : '手工配置'
}
function memberRuleDetail(row: any) {
const departments = Array.isArray(row.dept_names) && row.dept_names.length ? row.dept_names.join(' / ') : '未分部门'
return `${departments} · ${row.userid || '未绑定 userid'}`
}
function memberFilterLabel(member: any) {
const department = member.department_name || member.dept_name || ''
@@ -909,17 +840,17 @@ function formatCustomerRate(value: unknown) {
return `${Number(value || 0).toFixed(1)}%`
}
function formatNumber(value: unknown) {
return Number(value || 0).toLocaleString('zh-CN')
}
function formatNumber(value: unknown) {
return Number(value || 0).toLocaleString('zh-CN')
}
function formatPickerTime(value: unknown) {
const date = new Date(Number(value || 0) * 1000)
const pad = (number: number) => String(number).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
function formatPickerTime(value: unknown) {
const date = new Date(Number(value || 0) * 1000)
const pad = (number: number) => String(number).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
async function copyText(value: string, label: string) {
async function copyText(value: string, label: string) {
if (!value) return ElMessage.warning(`${label}暂无内容`)
try {
await navigator.clipboard.writeText(value)
@@ -930,8 +861,9 @@ async function copyText(value: string, label: string) {
textarea.style.opacity = '0'
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
textarea.remove()
const copied = document.execCommand('copy')
textarea.remove()
if (!copied) throw new Error('copy command failed')
}
ElMessage.success(`${label}已复制`)
}
@@ -1010,7 +942,7 @@ h1, h2, h3, p { margin: 0; }
.callback-list { margin: 14px 0 0; border-top: 1px solid rgba(124,150,157,.16); }.callback-list > div { display: grid; grid-template-columns: 120px 1fr 50px; align-items: center; min-height: 40px; border-bottom: 1px solid rgba(124,150,157,.12); font-size: 11px; }.callback-list dt { color: #657488; }.callback-list dd { overflow: hidden; margin: 0; color: #27374c; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; text-overflow: ellipsis; white-space: nowrap; }.callback-list button { border: 0; color: #148f83; background: transparent; cursor: pointer; }
.configuration-actions { display: flex; align-items: center; gap: 14px; margin-top: 16px; }
.install-pool-select { width: 220px; }
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; }.form-tip { display: block; margin-top: 5px; color: #8b97a6; font-size: 10px; }.link-form .el-select, .link-form .el-input-number { width: 100%; }
.form-grid, .rule-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 14px; }.form-tip { display: block; margin-top: 5px; color: #8b97a6; font-size: 10px; }.link-form .el-select, .link-form .el-input-number { width: 100%; }
@media (max-width: 1100px) { .heading-actions { flex-wrap: wrap; justify-content: flex-end; }.metric-grid, .customer-metric-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }.pool-layout { grid-template-columns: 210px minmax(0,1fr); }.pool-toolbar { align-items: flex-start; flex-direction: column; } }
@media (max-width: 760px) { .promotion-page { padding: 10px; }.page-header, .section-heading { align-items: flex-start; flex-direction: column; }.update-time { display: none; }.metric-grid, .customer-metric-grid, .form-grid { grid-template-columns: 1fr; }.tab-nav { overflow-x: auto; }.tab-nav button { min-width: 112px; }.tab-content { padding: 14px; }.pool-layout { grid-template-columns: 1fr; }.pool-sidebar { display: flex; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); }.pool-item { min-width: 190px; }.callback-list > div { grid-template-columns: 1fr 48px; padding: 8px 0; }.callback-list dt { grid-column: 1 / -1; }.install-pool-select { width: 100%; }.customer-heading-actions { width: 100%; justify-content: flex-end; }.customer-filter-bar :deep(.el-form-item) { width: 100%; margin-right: 0; }.customer-filter-bar :deep(.el-form-item__content), .customer-filter-bar .el-select { width: 100%; }.customer-filter-bar .filter-actions :deep(.el-form-item__content) { justify-content: flex-end; }.customer-pagination { align-items: flex-start; flex-direction: column; }.customer-pagination :deep(.el-pagination) { max-width: 100%; flex-wrap: wrap; justify-content: flex-start; } }
@media (max-width: 760px) { .promotion-page { padding: 10px; }.page-header, .section-heading { align-items: flex-start; flex-direction: column; }.update-time { display: none; }.metric-grid, .customer-metric-grid, .form-grid, .rule-form-grid { grid-template-columns: 1fr; }.tab-nav { overflow-x: auto; }.tab-nav button { min-width: 112px; }.tab-content { padding: 14px; }.pool-layout { grid-template-columns: 1fr; }.pool-sidebar { display: flex; overflow-x: auto; border-right: 0; border-bottom: 1px solid var(--line); }.pool-item { min-width: 190px; }.callback-list > div { grid-template-columns: 1fr 48px; padding: 8px 0; }.callback-list dt { grid-column: 1 / -1; }.install-pool-select { width: 100%; }.customer-heading-actions { width: 100%; justify-content: flex-end; }.customer-filter-bar :deep(.el-form-item) { width: 100%; margin-right: 0; }.customer-filter-bar :deep(.el-form-item__content), .customer-filter-bar .el-select { width: 100%; }.customer-filter-bar .filter-actions :deep(.el-form-item__content) { justify-content: flex-end; }.customer-pagination { align-items: flex-start; flex-direction: column; }.customer-pagination :deep(.el-pagination) { max-width: 100%; flex-wrap: wrap; justify-content: flex-start; } }
</style>
File diff suppressed because one or more lines are too long
+4 -3
View File
@@ -45,9 +45,10 @@ export default defineConfig(({ mode }) => {
: 'http://127.0.0.1:8080'
return {
base: '/admin/',
server: {
host: '0.0.0.0',
base: '/admin/',
server: {
port: 5555,
host: '0.0.0.0',
hmr: true,
open: true,
proxy: {
@@ -79,6 +79,33 @@ class WecomPromotionController extends BaseAdminController
)));
}
public function saveMember()
{
if (!$this->hasPagePermission()) {
return $this->fail('权限不足');
}
return $this->run(fn () => $this->success('成员分流规则已保存', WecomPromotionLogic::saveMember(
$this->request->post(),
$this->adminId,
$this->adminInfo
)));
}
public function toggleMember()
{
if (!$this->hasPagePermission()) {
return $this->fail('权限不足');
}
$id = (int) $this->request->post('id', 0);
$status = (int) $this->request->post('status', 0);
return $this->run(fn () => $this->success(
'成员状态已更新',
WecomPromotionLogic::toggleMember($id, $status, $this->adminId, $this->adminInfo)
));
}
public function checkApiPermission()
{
if (!$this->hasPagePermission()) {
@@ -7,6 +7,9 @@ namespace app\adminapi\logic\firstvisit;
use app\common\service\DataScope\DataScopeService;
use app\common\service\qywx\QywxCustomerAcquisitionApiService;
use app\common\service\qywx\QywxCustomerAcquisitionLinkService;
use app\common\service\qywx\QywxPromotionMemberSchedulerService;
use app\common\service\qywx\QywxPromotionRangeSyncService;
use app\common\service\qywx\QywxPromotionWeightedRandom;
use app\common\service\qywx\QywxPromotionWidgetService;
use RuntimeException;
use think\facade\Db;
@@ -16,6 +19,7 @@ class WecomPromotionLogic
{
public static function overview(int $adminId, array $adminInfo, string $domain): array
{
self::assertMemberDispatchSchema();
$visibleIds = DataScopeService::getVisibleAdminIds($adminId, $adminInfo);
$poolsQuery = Db::name('qywx_promotion_pool')->alias('p')
->leftJoin('admin u', 'u.id = p.owner_admin_id')
@@ -46,15 +50,12 @@ class WecomPromotionLogic
unset($pool['widget_config_json']);
$key = (string) $pool['public_key'];
$scriptUrl = $domain . '/api/qywx-promotion/js/' . $key;
$goUrl = $domain . '/api/qywx-promotion/go/' . $key;
$compatGoUrl = $domain . '/api/qywx-promotion/go/' . $key;
$pool['script_url'] = $scriptUrl;
$pool['go_url'] = $goUrl;
$pool['compat_go_url'] = $compatGoUrl;
$pool['install_code'] = '<script src="'
. htmlspecialchars($scriptUrl, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')
. '" defer></script>';
$pool['trigger_code'] = '<a href="'
. htmlspecialchars($goUrl, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')
. '" data-wecom-promotion="' . $key . '">添加企业微信</a>';
}
unset($pool);
@@ -70,12 +71,101 @@ class WecomPromotionLogic
if ((int) ($link['status'] ?? 0) === 1 && $link['valid_customer_acquisition_link']) {
$onlineLinks++;
}
if ((string) ($link['today_date'] ?? '') === $today) {
$todayClicks += (int) ($link['today_count'] ?? 0);
}
}
unset($link);
$memberOptions = self::memberOptions($adminId, $adminInfo);
$adminIdByUserId = [];
$memberOptionByAdminId = [];
foreach ($memberOptions as $member) {
$adminIdByUserId[(string) $member['userid']] = (int) $member['id'];
$memberOptionByAdminId[(int) $member['id']] = $member;
}
$linksByPool = [];
foreach ($links as $link) {
$linksByPool[(int) $link['pool_id']][] = $link;
}
self::backfillPoolMembers($pools, $linksByPool, $adminIdByUserId);
$memberRulesByPool = [];
$syncByPool = [];
if ($poolIds !== []) {
$memberRows = Db::name('qywx_promotion_pool_member')
->whereIn('pool_id', $poolIds)
->whereNull('delete_time')
->order('id', 'asc')
->select()->toArray();
foreach ($memberRows as $memberRow) {
$memberAdminId = (int) ($memberRow['admin_id'] ?? 0);
$option = $memberOptionByAdminId[$memberAdminId] ?? [];
$memberRow['name'] = (string) ($option['name'] ?? $memberRow['userid'] ?? '未知成员');
$memberRow['dept_names'] = array_values((array) ($option['dept_names'] ?? []));
$memberRow['status'] = (int) ($memberRow['enabled'] ?? 0);
$memberRow['today_count'] = (string) ($memberRow['today_date'] ?? '') === $today
? (int) ($memberRow['today_count'] ?? 0)
: 0;
$memberRulesByPool[(int) $memberRow['pool_id']][] = $memberRow;
$todayClicks += (int) $memberRow['today_count'];
}
foreach (Db::name('qywx_promotion_range_sync')->whereIn('pool_id', $poolIds)->select()->toArray() as $syncRow) {
$syncByPool[(int) $syncRow['pool_id']] = $syncRow;
}
}
foreach ($pools as &$pool) {
$poolLinks = $linksByPool[(int) $pool['id']] ?? [];
$officialLinks = array_values(array_filter(
$poolLinks,
static fn (array $link): bool => !empty($link['is_official'])
&& (int) ($link['remote_status'] ?? 0) !== 2
));
$legacyCount = count(array_filter(
$poolLinks,
static fn (array $link): bool => empty($link['is_official'])
));
// links 已按 id 倒序返回;旧多链接方案暂以最新官方链接作为主链接,
// 保存方案时会把其余链接仅在本地下线,保留远端链接与历史客户归因。
$officialLink = $officialLinks[0] ?? null;
$memberRules = $memberRulesByPool[(int) $pool['id']] ?? [];
$sync = $syncByPool[(int) $pool['id']] ?? [];
foreach ($memberRules as &$memberRule) {
$memberRule['is_current'] = (int) ($memberRule['id'] ?? 0)
=== (int) ($sync['desired_member_id'] ?? 0);
$memberRule['is_applied'] = (int) ($memberRule['id'] ?? 0)
=== (int) ($sync['applied_member_id'] ?? 0);
$memberRule['sync_status'] = (int) ($sync['status'] ?? 0);
$memberRule['sync_error'] = (string) ($sync['last_error'] ?? '');
}
unset($memberRule);
$memberAdminIds = [];
foreach ($memberRules as $memberRule) {
if ((int) ($memberRule['admin_id'] ?? 0) > 0) {
$memberAdminIds[] = (int) $memberRule['admin_id'];
}
}
$mainUrl = $officialLink === null
? ''
: QywxCustomerAcquisitionLinkService::withCustomerChannel(
(string) ($officialLink['wecom_url'] ?? ''),
'zyt_pool:' . (int) $pool['id']
);
$pool['official_link'] = $officialLink;
$pool['official_link_count'] = count($officialLinks);
$pool['legacy_link_count'] = $legacyCount;
$pool['member_admin_ids'] = array_values(array_unique($memberAdminIds));
$pool['member_rules'] = $memberRules;
$pool['dispatch_sync'] = $sync;
$pool['skip_verify'] = (int) ($officialLink['skip_verify'] ?? 0);
$pool['migration_state'] = count($officialLinks) > 1
? 'needs_resolution'
: ($officialLink === null ? ($legacyCount > 0 ? 'legacy_only' : 'missing') : 'ready');
$pool['main_url'] = $mainUrl;
// go_url 现在代表可直接分享的企业微信官方链接;compat_go_url 保留旧 302 入口。
$pool['go_url'] = $mainUrl;
$pool['trigger_code'] = $mainUrl === '' ? '' : '<a href="'
. htmlspecialchars($mainUrl, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')
. '" data-wecom-promotion="' . (string) $pool['public_key'] . '">添加企业微信</a>';
}
unset($pool);
$config = self::internalApplicationStatus($domain);
return [
@@ -92,14 +182,18 @@ class WecomPromotionLogic
],
'pools' => $pools,
'links' => $links,
'member_options' => self::memberOptions($adminId, $adminInfo),
'member_options' => $memberOptions,
'customer_acquisition_link_example' => QywxCustomerAcquisitionLinkService::example(),
];
}
public static function savePool(array $params, int $adminId, array $adminInfo): array
{
self::assertMemberDispatchSchema();
$id = max(0, (int) ($params['id'] ?? 0));
$existingPool = $id > 0
? self::assertScopedRow('qywx_promotion_pool', $id, $adminId, $adminInfo)
: null;
$name = trim((string) ($params['name'] ?? ''));
if ($name === '' || mb_strlen($name) > 60) {
throw new RuntimeException('请输入 1-60 个字符的分流方案名称');
@@ -108,28 +202,147 @@ class WecomPromotionLogic
if (!QywxCustomerAcquisitionLinkService::isAllowed($fallback, true)) {
throw new RuntimeException('兜底链接必须是企业微信获客助手生成的 HTTPS 链接');
}
$members = self::resolveMembers((array) ($params['member_admin_ids'] ?? []), $adminId, $adminInfo);
$userIds = array_values(array_column($members, 'userid'));
$selectedUserId = self::preferredDispatchUserId($id, $members);
$skipVerify = (int) ($params['skip_verify'] ?? 0) === 1 ? 1 : 0;
$status = (int) ($params['status'] ?? 1) === 1 ? 1 : 0;
$now = time();
$data = [
$poolData = [
'name' => $name,
'status' => (int) ($params['status'] ?? 1) === 1 ? 1 : 0,
'status' => $status,
'fallback_url' => $fallback,
'update_time' => $now,
];
if ($id > 0) {
self::assertScopedRow('qywx_promotion_pool', $id, $adminId, $adminInfo);
Db::name('qywx_promotion_pool')->where('id', $id)->update($data);
} else {
$data += [
'public_key' => bin2hex(random_bytes(16)),
'owner_admin_id' => $adminId,
'dept_id' => self::primaryDeptId($adminId),
'click_count' => 0,
'create_time' => $now,
];
$id = (int) Db::name('qywx_promotion_pool')->insertGetId($data);
$existingLink = null;
if ($existingPool !== null) {
$existingLink = Db::name('qywx_promotion_link')
->where('pool_id', $id)
->whereNull('delete_time')
->where('remote_link_id', '<>', '')
->where('remote_status', '<>', 2)
->order('id', 'desc')
->find();
}
return ['id' => $id];
$api = new QywxCustomerAcquisitionApiService();
$payload = [
'link_name' => mb_substr($name, 0, 30),
// 对外始终是同一个官方直链;当前只激活调度器选中的成员,回调后再切换下一位。
'range' => ['user_list' => [$selectedUserId]],
'skip_verify' => $skipVerify === 1,
];
$createdRemote = false;
if ($existingLink !== null) {
$remoteLinkId = trim((string) ($existingLink['remote_link_id'] ?? ''));
$payload['link_id'] = $remoteLinkId;
$api->updateLink($payload);
} else {
$created = $api->createLink($payload);
$remoteLinkId = self::extractRemoteLinkId($created);
if ($remoteLinkId === '') {
throw new RuntimeException('企业微信已创建链接,但接口未返回 link_id,请执行“同步企业微信”确认结果');
}
$createdRemote = true;
}
try {
$remote = self::normaliseRemoteLink($api->getLink($remoteLinkId), $remoteLinkId);
} catch (\Throwable $e) {
if ($createdRemote) {
try {
$api->deleteLink($remoteLinkId);
} catch (\Throwable) {
// 保留详情读取的原始异常;孤立链接仍可通过企业微信同步找回。
}
}
throw $e;
}
$remoteData = self::remoteColumns($remote, $now);
$linkId = (int) ($existingLink['id'] ?? 0);
try {
Db::transaction(function () use (
&$id,
&$linkId,
$poolData,
$remoteData,
$status,
$existingPool,
$members,
$selectedUserId,
$now,
$adminId
): void {
if ($existingPool === null) {
$id = (int) Db::name('qywx_promotion_pool')->insertGetId($poolData + [
'public_key' => bin2hex(random_bytes(16)),
'owner_admin_id' => $adminId,
'dept_id' => self::primaryDeptId($adminId),
'click_count' => 0,
'create_time' => $now,
]);
} else {
Db::name('qywx_promotion_pool')->where('id', $id)->update($poolData);
}
$linkCommon = [
'pool_id' => $id,
'group_name' => '方案官方链接',
'status' => $status,
'update_time' => $now,
];
if ($linkId > 0) {
Db::name('qywx_promotion_link')->where('id', $linkId)->update($remoteData + $linkCommon);
} else {
$linkId = (int) Db::name('qywx_promotion_link')->insertGetId($remoteData + $linkCommon + [
'account_id' => 0,
'weight' => 1,
'daily_limit' => 0,
'today_count' => 0,
'today_date' => null,
'active_start' => 0,
'active_end' => 0,
'click_count' => 0,
'last_click_time' => 0,
'owner_admin_id' => (int) ($existingPool['owner_admin_id'] ?? 0) ?: $adminId,
'dept_id' => (int) ($existingPool['dept_id'] ?? 0) ?: self::primaryDeptId($adminId),
'remark' => '',
'create_time' => $now,
]);
}
self::persistPoolMembers($id, $members, $now);
QywxPromotionMemberSchedulerService::initialisePool($id, $linkId, $selectedUserId);
// 旧多链接只在本地下线,企业微信远端与历史客户归因继续保留。
Db::name('qywx_promotion_link')
->where('pool_id', $id)
->where('id', '<>', $linkId)
->whereNull('delete_time')
->update(['status' => 0, 'update_time' => $now]);
});
} catch (\Throwable $e) {
if ($createdRemote) {
try {
$api->deleteLink($remoteLinkId);
} catch (\Throwable) {
// 企业微信补偿失败时保留原始异常;可通过官方列表找回孤立链接。
}
}
throw $e;
}
return [
'id' => $id,
'remote_link_id' => (string) ($remote['link_id'] ?? ''),
'wecom_url' => (string) ($remote['url'] ?? ''),
'main_url' => QywxCustomerAcquisitionLinkService::withCustomerChannel(
(string) ($remote['url'] ?? ''),
'zyt_pool:' . $id
),
'member_userids' => $userIds,
'current_userid' => $selectedUserId,
];
}
public static function saveWidget(array $params, int $adminId, array $adminInfo): array
@@ -154,15 +367,109 @@ class WecomPromotionLogic
Db::transaction(function () use ($id, $now): void {
Db::name('qywx_promotion_pool')->where('id', $id)->update(['delete_time' => $now, 'update_time' => $now]);
Db::name('qywx_promotion_link')->where('pool_id', $id)->whereNull('delete_time')->update(['delete_time' => $now, 'update_time' => $now]);
Db::name('qywx_promotion_pool_member')->where('pool_id', $id)->whereNull('delete_time')->update([
'enabled' => 0,
'delete_time' => $now,
'update_time' => $now,
]);
Db::name('qywx_promotion_range_sync')->where('pool_id', $id)->update([
'status' => 4,
'next_retry' => 0,
'last_error' => '分流方案已删除',
'update_time' => $now,
]);
});
}
public static function saveMember(array $params, int $adminId, array $adminInfo): array
{
self::assertMemberDispatchSchema();
$id = max(0, (int) ($params['id'] ?? 0));
$member = Db::name('qywx_promotion_pool_member')->where('id', $id)->whereNull('delete_time')->find();
if (!$member) {
throw new RuntimeException('分流成员不存在或已移除');
}
$poolId = (int) $member['pool_id'];
self::assertScopedRow('qywx_promotion_pool', $poolId, $adminId, $adminInfo);
$enabled = (int) ($params['status'] ?? $params['enabled'] ?? 1) === 1 ? 1 : 0;
if ($enabled === 0) {
$otherEnabled = (int) Db::name('qywx_promotion_pool_member')
->where('pool_id', $poolId)
->where('id', '<>', $id)
->where('enabled', 1)
->whereNull('delete_time')
->count();
if ($otherEnabled <= 0) {
throw new RuntimeException('至少需要保留一名启用的获客医助');
}
}
$startAt = self::parseTime($params['active_start'] ?? null);
$endAt = self::parseTime($params['active_end'] ?? null);
if ($startAt > 0 && $endAt > 0 && $endAt <= $startAt) {
throw new RuntimeException('生效结束时间必须晚于开始时间');
}
$now = time();
Db::transaction(function () use ($id, $enabled, $params, $startAt, $endAt, $now): void {
Db::name('qywx_promotion_pool_member')->where('id', $id)->update([
'enabled' => $enabled,
'weight' => min(100, max(1, (int) ($params['weight'] ?? 1))),
'daily_limit' => min(1000000, max(0, (int) ($params['daily_limit'] ?? 0))),
'active_start' => $startAt,
'active_end' => $endAt,
'remark' => mb_substr(trim((string) ($params['remark'] ?? '')), 0, 255),
'update_time' => $now,
]);
});
$planned = QywxPromotionMemberSchedulerService::reconcilePool($poolId);
$syncError = '';
if ($planned['queued']) {
try {
(new QywxPromotionRangeSyncService())->syncPool($poolId);
} catch (\Throwable $e) {
// 本地规则已保存;后台分钟任务会继续重试,不把成员状态回滚成错误值。
$syncError = $e->getMessage();
}
}
return ['id' => $id, 'pool_id' => $poolId, 'dispatch' => $planned, 'sync_error' => $syncError];
}
public static function toggleMember(int $id, int $status, int $adminId, array $adminInfo): array
{
self::assertMemberDispatchSchema();
$row = Db::name('qywx_promotion_pool_member')->where('id', $id)->whereNull('delete_time')->find();
if (!$row) {
throw new RuntimeException('分流成员不存在或已移除');
}
return self::saveMember([
'id' => $id,
'status' => $status,
'weight' => (int) ($row['weight'] ?? 1),
'daily_limit' => (int) ($row['daily_limit'] ?? 0),
'active_start' => (int) ($row['active_start'] ?? 0),
'active_end' => (int) ($row['active_end'] ?? 0),
'remark' => (string) ($row['remark'] ?? ''),
], $adminId, $adminInfo);
}
public static function saveLink(array $params, int $adminId, array $adminInfo): array
{
$id = max(0, (int) ($params['id'] ?? 0));
$poolId = max(0, (int) ($params['pool_id'] ?? 0));
$pool = self::assertScopedRow('qywx_promotion_pool', $poolId, $adminId, $adminInfo);
$existing = $id > 0 ? self::assertScopedRow('qywx_promotion_link', $id, $adminId, $adminInfo) : null;
if ($existing === null) {
$officialCount = (int) Db::name('qywx_promotion_link')
->where('pool_id', $poolId)
->whereNull('delete_time')
->where('remote_link_id', '<>', '')
->where('remote_status', '<>', 2)
->count();
if ($officialCount > 0) {
throw new RuntimeException('一个分流方案只能有一个官方获客链接,请直接编辑分流方案中的获客成员');
}
}
$name = trim((string) ($params['name'] ?? ''));
if ($name === '' || mb_strlen($name) > 80) {
throw new RuntimeException('请输入 1-80 个字符的获客链接名称');
@@ -438,8 +745,8 @@ class WecomPromotionLogic
return $result;
}
/** @return list<string> */
private static function resolveMemberUserIds(array $adminIds, int $adminId, array $adminInfo): array
/** @return list<array{id:int,name:string,userid:string,dept_ids:list<int>,dept_names:list<string>}> */
private static function resolveMembers(array $adminIds, int $adminId, array $adminInfo): array
{
$requested = array_values(array_unique(array_filter(array_map('intval', $adminIds))));
if ($requested === []) {
@@ -447,47 +754,225 @@ class WecomPromotionLogic
}
$available = [];
foreach (self::memberOptions($adminId, $adminInfo) as $member) {
$available[$member['id']] = $member['userid'];
$available[(int) $member['id']] = $member;
}
$userIds = [];
$members = [];
foreach ($requested as $requestedId) {
if (!isset($available[$requestedId])) {
throw new RuntimeException('选择的获客成员超出当前角色或部门的数据范围,或尚未绑定企业微信 userid');
}
$userIds[] = $available[$requestedId];
$members[] = $available[$requestedId];
}
if (count($userIds) > 500) {
if (count($members) > 500) {
throw new RuntimeException('单个获客链接最多配置 500 名成员');
}
return array_values(array_unique($userIds));
return $members;
}
/** @return list<string> */
private static function resolveMemberUserIds(array $adminIds, int $adminId, array $adminInfo): array
{
return array_values(array_column(self::resolveMembers($adminIds, $adminId, $adminInfo), 'userid'));
}
/** @param list<array{id:int,userid:string}> $members */
private static function preferredDispatchUserId(int $poolId, array $members): string
{
if ($members === []) {
throw new RuntimeException('请至少选择一名获客成员');
}
$selected = [];
foreach ($members as $member) {
$selected[(string) $member['userid']] = true;
}
$rules = $poolId > 0
? Db::name('qywx_promotion_pool_member')->where('pool_id', $poolId)->whereNull('delete_time')->select()->toArray()
: [];
$rulesById = [];
$rulesByUserId = [];
foreach ($rules as $rule) {
$rulesById[(int) $rule['id']] = $rule;
$rulesByUserId[(string) $rule['userid']] = $rule;
}
$desiredId = $poolId > 0
? (int) (Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->value('desired_member_id') ?? 0)
: 0;
$now = time();
$today = date('Y-m-d', $now);
if (isset($rulesById[$desiredId])) {
$current = $rulesById[$desiredId];
if ((string) ($current['today_date'] ?? '') !== $today) {
$current['today_count'] = 0;
$current['today_date'] = $today;
}
if (isset($selected[(string) $current['userid']]) && QywxPromotionWeightedRandom::eligible($current, $now)) {
return (string) $current['userid'];
}
}
$randomCandidates = [];
$candidateUserIds = [];
foreach ($members as $index => $member) {
$userId = (string) $member['userid'];
$rule = $rulesByUserId[$userId] ?? [
'enabled' => 1,
'weight' => 1,
'daily_limit' => 0,
'today_count' => 0,
'today_date' => $today,
'active_start' => 0,
'active_end' => 0,
];
if ((string) ($rule['today_date'] ?? '') !== $today) {
$rule['today_count'] = 0;
$rule['today_date'] = $today;
}
$candidateId = $index + 1;
$rule['id'] = $candidateId;
$randomCandidates[] = $rule;
$candidateUserIds[$candidateId] = $userId;
}
$selection = QywxPromotionWeightedRandom::select($randomCandidates, $today, $now);
$selectedCandidateId = (int) ($selection['selected_id'] ?? 0);
if ($selectedCandidateId > 0 && isset($candidateUserIds[$selectedCandidateId])) {
return $candidateUserIds[$selectedCandidateId];
}
// 企业微信不接受空范围;仅在所有启用成员恰好达到上限时保留一名,队列会标记“无可用成员”。
foreach ($members as $member) {
$rule = $rulesByUserId[(string) $member['userid']] ?? null;
if ($rule === null || (int) ($rule['enabled'] ?? 1) === 1) {
return (string) $member['userid'];
}
}
throw new RuntimeException('至少需要启用一名获客医助');
}
/** @param list<array{id:int,userid:string}> $members */
private static function persistPoolMembers(int $poolId, array $members, int $now): void
{
$selectedUserIds = [];
foreach ($members as $member) {
$userId = (string) $member['userid'];
$selectedUserIds[] = $userId;
$existing = Db::name('qywx_promotion_pool_member')
->where('pool_id', $poolId)->where('userid', $userId)->find();
if ($existing) {
Db::name('qywx_promotion_pool_member')->where('id', (int) $existing['id'])->update([
'admin_id' => (int) $member['id'],
'userid' => $userId,
'delete_time' => null,
'update_time' => $now,
]);
continue;
}
Db::name('qywx_promotion_pool_member')->insert([
'pool_id' => $poolId,
'admin_id' => (int) $member['id'],
'userid' => $userId,
'enabled' => 1,
'weight' => 1,
'current_weight' => 0,
'daily_limit' => 0,
'today_count' => 0,
'today_date' => null,
'total_count' => 0,
'active_start' => 0,
'active_end' => 0,
'last_assigned_time' => 0,
'remark' => '',
'create_time' => $now,
'update_time' => $now,
]);
}
$removeQuery = Db::name('qywx_promotion_pool_member')
->where('pool_id', $poolId)->whereNull('delete_time');
if ($selectedUserIds !== []) {
$removeQuery->whereNotIn('userid', $selectedUserIds);
}
$removeQuery->update(['delete_time' => $now, 'enabled' => 0, 'update_time' => $now]);
}
/**
* 旧版方案第一次打开时,把官方链接原有 range.user_list 回填为成员规则;不修改远端链接。
*
* @param list<array<string,mixed>> $pools
* @param array<int,list<array<string,mixed>>> $linksByPool
* @param array<string,int> $adminIdByUserId
*/
private static function backfillPoolMembers(array $pools, array $linksByPool, array $adminIdByUserId): void
{
$now = time();
foreach ($pools as $pool) {
$poolId = (int) ($pool['id'] ?? 0);
if ($poolId <= 0 || Db::name('qywx_promotion_pool_member')->where('pool_id', $poolId)->whereNull('delete_time')->count() > 0) {
continue;
}
$officialLink = null;
foreach ($linksByPool[$poolId] ?? [] as $link) {
if (!empty($link['is_official']) && (int) ($link['remote_status'] ?? 0) !== 2) {
$officialLink = $link;
break;
}
}
if ($officialLink === null) {
continue;
}
$firstUserId = '';
foreach ((array) ($officialLink['range_userids'] ?? []) as $userIdValue) {
$userId = trim((string) $userIdValue);
$mappedAdminId = (int) ($adminIdByUserId[$userId] ?? 0);
if ($userId === '' || $mappedAdminId <= 0) {
continue;
}
if ($firstUserId === '') {
$firstUserId = $userId;
}
try {
Db::name('qywx_promotion_pool_member')->insert([
'pool_id' => $poolId,
'admin_id' => $mappedAdminId,
'userid' => $userId,
'enabled' => 1,
'weight' => 1,
'current_weight' => 0,
'daily_limit' => 0,
'today_count' => 0,
'today_date' => null,
'total_count' => 0,
'active_start' => 0,
'active_end' => 0,
'last_assigned_time' => 0,
'remark' => '',
'create_time' => $now,
'update_time' => $now,
]);
} catch (\Throwable) {
// 并发打开 overview 时唯一键会阻止重复回填。
}
}
if ($firstUserId !== '') {
QywxPromotionMemberSchedulerService::initialisePool(
$poolId,
(int) $officialLink['id'],
$firstUserId
);
// 旧链接可能仍包含多人范围;排队收敛为当前调度成员,官方 URL 本身保持不变。
Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->update([
'status' => 1,
'applied_member_id' => 0,
'applied_version' => 0,
'next_retry' => $now,
'update_time' => $now,
]);
}
}
}
/** @return array<string,mixed> */
private static function normaliseRemoteLink(array $response, string $fallbackId = ''): array
{
$link = isset($response['link']) && is_array($response['link']) ? $response['link'] : $response;
$linkId = trim((string) ($link['link_id'] ?? $response['link_id'] ?? $fallbackId));
$url = trim((string) ($link['url'] ?? $link['link_url'] ?? $response['url'] ?? ''));
if ($linkId === '') {
throw new RuntimeException('企业微信获客链接详情缺少 link_id');
}
if (!QywxCustomerAcquisitionLinkService::isAllowed($url)) {
throw new RuntimeException('企业微信获客链接详情未返回有效的 https://work.weixin.qq.com/ca/... 地址');
}
$range = isset($link['range']) && is_array($link['range']) ? $link['range'] : [];
return [
'link_id' => $linkId,
'link_name' => trim((string) ($link['link_name'] ?? $link['name'] ?? $linkId)),
'url' => $url,
'create_time' => max(0, (int) ($link['create_time'] ?? 0)),
'range_userids' => self::normaliseScalarList($range['user_list'] ?? []),
'range_department_ids' => self::normaliseScalarList($range['department_list'] ?? []),
'skip_verify' => !empty($link['skip_verify']),
'priority_option' => isset($link['priority_option']) && is_array($link['priority_option']) ? $link['priority_option'] : [],
'snapshot' => $link,
];
return QywxCustomerAcquisitionLinkService::normaliseRemoteResponse($response, $fallbackId);
}
/** @return array<string,mixed> */
@@ -681,6 +1166,19 @@ class WecomPromotionLogic
return $time === false ? 0 : $time;
}
private static function assertMemberDispatchSchema(): void
{
try {
Db::name('qywx_promotion_pool_member')->limit(1)->find();
Db::name('qywx_promotion_dispatch_event')->limit(1)->find();
Db::name('qywx_promotion_range_sync')->limit(1)->find();
} catch (\Throwable $e) {
throw new RuntimeException(
'获客成员调度数据表尚未安装,请先执行 server/sql/1.9.20260824/upgrade_qywx_promotion_member_dispatch.sql'
);
}
}
private static function mask(string $value): string
{
$length = strlen($value);
@@ -742,7 +1240,7 @@ class WecomPromotionLogic
'callback_ready' => $callbackTokenConfigured && $callbackAesConfigured,
// 复用自建应用现有的「API 接收消息」入口;获客助手事件与其他应用事件
// 由同一个控制器按 Event/ChangeType 分发,不需要再配置第二个回调地址。
'callback_url' => rtrim($domain, '/') . '/api/QywxExternalContactCallback/notify',
'callback_url' => rtrim($domain, '/') . '/api/qywx/external-contact/notify',
'official_doc' => 'https://developer.work.weixin.qq.com/document/path/97297',
];
}
@@ -6,6 +6,8 @@ namespace app\api\controller;
use app\adminapi\logic\qywx\CustomerLogic;
use app\common\service\qywx\QywxCustomerAcquisitionCustomerService;
use app\common\service\qywx\QywxPromotionMemberSchedulerService;
use app\common\service\qywx\QywxPromotionRangeSyncService;
use EasyWeChat\Kernel\Exceptions\BadRequestException;
use EasyWeChat\Work\Application;
use EasyWeChat\Work\Message;
@@ -178,6 +180,29 @@ class QywxExternalContactCallbackController extends BaseApiController
return;
}
if ($changeType === 'add_external_contact' && $state !== '' && $userId !== '') {
// customer_channel=zyt_pool:{id} 会原样进入 State;以实际 UserID 幂等记账并规划下一位。
try {
$dispatch = QywxPromotionMemberSchedulerService::recordFromState(
$state,
$userId,
$extId,
$eventTime,
'external_contact'
);
if (($dispatch['status'] ?? '') === 'counted' && (int) ($dispatch['pool_id'] ?? 0) > 0) {
try {
// 回调后立即切换;分钟任务仍负责网络异常、并发版本变化等情况的兜底重试。
(new QywxPromotionRangeSyncService())->syncPool((int) $dispatch['pool_id']);
} catch (\Throwable $e) {
Log::warning('qywx promotion immediate range sync failed: ' . $e->getMessage());
}
}
} catch (\Throwable $e) {
// 客户资料同步与成员调度互不阻塞;调度异常保留日志,获客会话回调仍可补偿。
Log::error('qywx promotion callback dispatch failed: ' . $e->getMessage(), ['exception' => $e]);
}
}
// 其余变更(添加/编辑/转接成功/标签变化等):以 get 详情为准 UPSERT,避免遗漏未枚举的 ChangeType
CustomerLogic::upsertSingleExternalContactFromApi($extId);
}
@@ -20,13 +20,13 @@ class QywxPromotionPublicController extends BaseApiController
return response('/* promotion pool not found */', 404, ['Content-Type' => 'application/javascript; charset=utf-8']);
}
// 由安装脚本自身的 src 解析 API 域名,避免把请求 Host 写入可公开缓存的 JavaScript。
$goUrl = '/api/qywx-promotion/go/' . $key;
$targetUrl = (string) ($pool['target_url'] ?? '');
$config = QywxPromotionWidgetService::decode($pool['widget_config_json'] ?? null);
$javascript = QywxPromotionWidgetService::renderScript(
$key,
$goUrl,
$targetUrl,
$config,
(int) ($pool['status'] ?? 0) === 1
(int) ($pool['status'] ?? 0) === 1 && $targetUrl !== ''
);
return response($javascript, 200, [
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace app\command;
use app\common\service\qywx\QywxPromotionRangeSyncService;
use think\console\Command;
use think\console\Input;
use think\console\Output;
/** 重试回调调度后尚未同步到企业微信的获客链接成员范围。 */
class QywxSyncPromotionRanges extends Command
{
protected function configure()
{
$this->setName('qywx:sync-promotion-ranges')
->setDescription('同步企业微信官方获客链接的下一名承接成员');
}
protected function execute(Input $input, Output $output): int
{
$result = (new QywxPromotionRangeSyncService())->syncPending(100);
$output->writeln(sprintf(
'QYWX_PROMOTION_RANGE_SYNC selected=%d synced=%d failed=%d',
$result['selected'],
$result['synced'],
$result['failed']
));
return 0;
}
}
@@ -183,11 +183,18 @@ class QywxCustomerAcquisitionApiService
return $this->request($method, $path, $body, true);
}
$errorMessage = trim((string) ($decoded['errmsg'] ?? '未知错误')) ?: '未知错误';
if ($errcode === 60111) {
throw new RuntimeException(
'所选医助的企业微信 userid 不存在,或不在获客助手可调用应用的可见范围;'
. '请检查后台账号绑定和企业微信应用可见范围。企业微信返回:' . $errorMessage
);
}
throw new RuntimeException(sprintf(
'企业微信获客助手接口失败[%d]%s',
$errcode,
trim((string) ($decoded['errmsg'] ?? '未知错误')) ?: '未知错误'
$errorMessage
));
}
@@ -93,6 +93,13 @@ class QywxCustomerAcquisitionCustomerService
'event_time' => $eventTime,
'snapshot' => $message,
], false);
self::recordPromotionAssignment(
(string) ($message['State'] ?? $message['state'] ?? ''),
$remoteLinkId,
$userId,
$externalUserId,
$eventTime
);
self::finishEvent($eventId, 1, '', $remoteLinkId, $externalUserId, $userId);
return ['duplicate' => false, 'status' => 'success'];
@@ -126,6 +133,13 @@ class QywxCustomerAcquisitionCustomerService
'event_time' => $eventTime,
'snapshot' => $chat,
], true);
self::recordPromotionAssignment(
(string) ($chatInfo['state'] ?? $message['State'] ?? ''),
$remoteLinkId,
$userId,
$externalUserId,
$eventTime
);
self::finishEvent($eventId, 1, '', $remoteLinkId, $externalUserId, $userId);
return ['duplicate' => false, 'status' => 'success'];
@@ -419,6 +433,40 @@ class QywxCustomerAcquisitionCustomerService
return [$adminId, $deptId];
}
private static function recordPromotionAssignment(
string $state,
string $remoteLinkId,
string $userId,
string $externalUserId,
int $eventTime
): void {
$result = QywxPromotionMemberSchedulerService::recordFromState(
$state,
$userId,
$externalUserId,
$eventTime,
'customer_acquisition'
);
if ((int) ($result['pool_id'] ?? 0) <= 0) {
$result = QywxPromotionMemberSchedulerService::recordFromRemoteLink(
$remoteLinkId,
$userId,
$externalUserId,
$eventTime,
'customer_acquisition'
);
}
if (($result['status'] ?? '') !== 'counted' || (int) ($result['pool_id'] ?? 0) <= 0) {
return;
}
try {
// 优先在本次回调完成后切换,后台分钟任务继续承担失败重试。
(new QywxPromotionRangeSyncService())->syncPool((int) $result['pool_id']);
} catch (\Throwable) {
// 同步服务已经保存失败原因和下次重试时间,不能让远端网络错误回滚已记账的客户。
}
}
private static function encodeJson(mixed $value): string
{
$json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace app\common\service\qywx;
use RuntimeException;
/** 企业微信获客助手链接校验。 */
class QywxCustomerAcquisitionLinkService
{
@@ -39,4 +41,98 @@ class QywxCustomerAcquisitionLinkService
{
return 'https://work.weixin.qq.com/ca/xxxxxxxx';
}
/**
* 规范化企业微信 create_link/get 返回的链接详情。
*
* get 接口把 range、priority_option 放在响应根级,link 只包含链接本身;
* 旧响应或测试桩可能把这些字段放在 link 内,因此保留兼容回退。
*
* @return array{
* link_id:string,
* link_name:string,
* url:string,
* create_time:int,
* range_userids:list<string>,
* range_department_ids:list<string>,
* skip_verify:bool,
* priority_option:array<string,mixed>,
* snapshot:array<string,mixed>
* }
*/
public static function normaliseRemoteResponse(array $response, string $fallbackId = ''): array
{
$link = isset($response['link']) && is_array($response['link']) ? $response['link'] : $response;
$range = isset($response['range']) && is_array($response['range'])
? $response['range']
: (isset($link['range']) && is_array($link['range']) ? $link['range'] : []);
$priorityOption = isset($response['priority_option']) && is_array($response['priority_option'])
? $response['priority_option']
: (isset($link['priority_option']) && is_array($link['priority_option']) ? $link['priority_option'] : []);
$linkId = trim((string) ($link['link_id'] ?? $response['link_id'] ?? $fallbackId));
$url = trim((string) ($link['url'] ?? $link['link_url'] ?? $response['url'] ?? ''));
if ($linkId === '') {
throw new RuntimeException('企业微信获客链接详情缺少 link_id');
}
if (!self::isAllowed($url)) {
throw new RuntimeException('企业微信获客链接详情未返回有效的 https://work.weixin.qq.com/ca/... 地址');
}
return [
'link_id' => $linkId,
'link_name' => trim((string) ($link['link_name'] ?? $link['name'] ?? $linkId)),
'url' => $url,
'create_time' => max(0, (int) ($link['create_time'] ?? 0)),
'range_userids' => self::normaliseScalarList($range['user_list'] ?? []),
'range_department_ids' => self::normaliseScalarList($range['department_list'] ?? []),
'skip_verify' => !empty($link['skip_verify']),
'priority_option' => $priorityOption,
'snapshot' => $response,
];
}
/** 追加或替换企业微信获客助手的自定义渠道标识。 */
public static function withCustomerChannel(string $url, string $channel): string
{
$url = trim($url);
$channel = trim($channel);
if (!self::isAllowed($url) || $channel === '' || strlen($channel) > 64) {
return '';
}
// 冒号在查询参数中是合法字符,保留“命名空间:编号”的可读结构;其余字符仍编码。
$parameter = 'customer_channel=' . str_replace('%3A', ':', rawurlencode($channel));
if (preg_match('/([?&])customer_channel=[^&#]*/i', $url) === 1) {
return (string) preg_replace_callback(
'/([?&])customer_channel=[^&#]*/i',
static fn (array $matches): string => $matches[1] . $parameter,
$url,
1
);
}
$fragment = '';
$fragmentPosition = strpos($url, '#');
if ($fragmentPosition !== false) {
$fragment = substr($url, $fragmentPosition);
$url = substr($url, 0, $fragmentPosition);
}
return $url . (str_contains($url, '?') ? '&' : '?') . $parameter . $fragment;
}
/** @return list<string> */
private static function normaliseScalarList(mixed $values): array
{
$result = [];
$seen = [];
foreach ((array) $values as $value) {
$normalised = trim((string) $value);
$key = 'value:' . $normalised;
if ($normalised !== '' && !isset($seen[$key])) {
$seen[$key] = true;
$result[] = $normalised;
}
}
return $result;
}
}
@@ -0,0 +1,335 @@
<?php
declare(strict_types=1);
namespace app\common\service\qywx;
use think\facade\Db;
/** 根据实际获客回调记账,并为同一个官方链接规划下一名承接成员。 */
class QywxPromotionMemberSchedulerService
{
public static function poolIdFromState(string $state): int
{
$state = trim($state);
return preg_match('/^zyt_pool:(\d+)$/', $state, $matches) === 1
? max(0, (int) $matches[1])
: 0;
}
/** @return array{status:string,pool_id:int,member_id:int,next_member_id:int} */
public static function recordFromState(
string $state,
string $userId,
string $externalUserId,
int $eventTime = 0,
string $source = 'external_contact'
): array {
$poolId = self::poolIdFromState($state);
if ($poolId <= 0) {
return ['status' => 'ignored_state', 'pool_id' => 0, 'member_id' => 0, 'next_member_id' => 0];
}
return self::record($poolId, $userId, $externalUserId, $eventTime, $source);
}
/** @return array{status:string,pool_id:int,member_id:int,next_member_id:int} */
public static function recordFromRemoteLink(
string $remoteLinkId,
string $userId,
string $externalUserId,
int $eventTime = 0,
string $source = 'customer_acquisition'
): array {
$poolId = (int) (Db::name('qywx_promotion_link')
->where('remote_link_id', trim($remoteLinkId))
->whereNull('delete_time')
->value('pool_id') ?? 0);
if ($poolId <= 0) {
return ['status' => 'ignored_link', 'pool_id' => 0, 'member_id' => 0, 'next_member_id' => 0];
}
return self::record($poolId, $userId, $externalUserId, $eventTime, $source);
}
/**
* 管理端变更成员开关、权重或上限后,确保当前远端成员仍可用;必要时立即排队切换。
*
* @return array{pool_id:int,next_member_id:int,queued:bool,blocked:bool}
*/
public static function reconcilePool(int $poolId): array
{
return Db::transaction(function () use ($poolId): array {
$now = time();
$today = date('Y-m-d', $now);
$linkId = self::promotionLinkId($poolId);
$sync = self::lockedSyncRow($poolId);
$members = self::lockedMembers($poolId);
if ($linkId <= 0 || $members === []) {
return ['pool_id' => $poolId, 'next_member_id' => 0, 'queued' => false, 'blocked' => true];
}
$desiredId = (int) ($sync['desired_member_id'] ?? 0);
$desiredEligible = false;
foreach ($members as &$member) {
if ((string) ($member['today_date'] ?? '') !== $today) {
$member['today_date'] = $today;
$member['today_count'] = 0;
}
if ((int) $member['id'] === $desiredId) {
$desiredEligible = QywxPromotionWeightedRandom::eligible($member, $now);
}
}
unset($member);
self::persistMemberCursors($members, $now);
if ($desiredEligible) {
if ((int) ($sync['status'] ?? 0) === 4) {
Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->update([
'status' => 0,
'next_retry' => 0,
'last_error' => '',
'update_time' => $now,
]);
}
return ['pool_id' => $poolId, 'next_member_id' => $desiredId, 'queued' => false, 'blocked' => false];
}
return self::selectAndQueueLocked($poolId, $linkId, $sync, $members, $today, $now);
});
}
public static function initialisePool(int $poolId, int $promotionLinkId, string $selectedUserId): int
{
$memberId = (int) (Db::name('qywx_promotion_pool_member')
->where('pool_id', $poolId)
->where('userid', $selectedUserId)
->whereNull('delete_time')
->value('id') ?? 0);
if ($memberId <= 0 || $promotionLinkId <= 0) {
return 0;
}
$now = time();
$existing = Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->find();
$data = [
'promotion_link_id' => $promotionLinkId,
'desired_member_id' => $memberId,
'applied_member_id' => $memberId,
'status' => 0,
'attempts' => 0,
'next_retry' => 0,
'lock_token' => '',
'lock_until' => 0,
'last_error' => '',
'update_time' => $now,
];
if ($existing) {
$version = max(1, (int) ($existing['desired_version'] ?? 0) + 1);
$data['desired_version'] = $version;
$data['applied_version'] = $version;
Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->update($data);
} else {
$data += ['pool_id' => $poolId, 'desired_version' => 1, 'applied_version' => 1, 'create_time' => $now];
Db::name('qywx_promotion_range_sync')->insert($data);
}
return $memberId;
}
/** @return array{status:string,pool_id:int,member_id:int,next_member_id:int} */
private static function record(
int $poolId,
string $userId,
string $externalUserId,
int $eventTime,
string $source
): array {
$userId = trim($userId);
$externalUserId = trim($externalUserId);
if ($poolId <= 0 || $userId === '' || $externalUserId === '') {
return ['status' => 'ignored_identity', 'pool_id' => $poolId, 'member_id' => 0, 'next_member_id' => 0];
}
return Db::transaction(function () use ($poolId, $userId, $externalUserId, $eventTime, $source): array {
$pool = Db::name('qywx_promotion_pool')->where('id', $poolId)->whereNull('delete_time')->lock(true)->find();
if (!$pool) {
return ['status' => 'ignored_pool', 'pool_id' => $poolId, 'member_id' => 0, 'next_member_id' => 0];
}
$members = self::lockedMembers($poolId);
$actualMember = null;
foreach ($members as $member) {
if ((string) ($member['userid'] ?? '') === $userId) {
$actualMember = $member;
break;
}
}
if ($actualMember === null) {
return ['status' => 'ignored_member', 'pool_id' => $poolId, 'member_id' => 0, 'next_member_id' => 0];
}
$actualMemberId = (int) $actualMember['id'];
$eventKey = hash('sha256', $poolId . '|' . $userId . '|' . $externalUserId);
try {
Db::name('qywx_promotion_dispatch_event')->insert([
'event_key' => $eventKey,
'pool_id' => $poolId,
'member_id' => $actualMemberId,
'userid' => $userId,
'external_userid' => $externalUserId,
'source' => mb_substr($source, 0, 32),
'event_time' => max(0, $eventTime),
'create_time' => time(),
]);
} catch (\Throwable $e) {
if (!Db::name('qywx_promotion_dispatch_event')->where('event_key', $eventKey)->find()) {
throw $e;
}
return ['status' => 'duplicate', 'pool_id' => $poolId, 'member_id' => $actualMemberId, 'next_member_id' => 0];
}
$now = time();
$today = date('Y-m-d', $now);
foreach ($members as &$member) {
if ((string) ($member['today_date'] ?? '') !== $today) {
$member['today_date'] = $today;
$member['today_count'] = 0;
}
if ((int) $member['id'] === $actualMemberId) {
$member['today_count'] = (int) ($member['today_count'] ?? 0) + 1;
$member['total_count'] = (int) ($member['total_count'] ?? 0) + 1;
$member['last_assigned_time'] = max($now, max(0, $eventTime));
}
}
unset($member);
self::persistMemberCursors($members, $now);
$linkId = self::promotionLinkId($poolId);
$sync = self::lockedSyncRow($poolId);
$desiredId = (int) ($sync['desired_member_id'] ?? 0);
if ($linkId <= 0 || ($desiredId > 0 && $desiredId !== $actualMemberId)) {
return ['status' => 'counted_stale', 'pool_id' => $poolId, 'member_id' => $actualMemberId, 'next_member_id' => $desiredId];
}
$planned = self::selectAndQueueLocked($poolId, $linkId, $sync, $members, $today, $now);
return [
'status' => $planned['blocked'] ? 'counted_blocked' : 'counted',
'pool_id' => $poolId,
'member_id' => $actualMemberId,
'next_member_id' => $planned['next_member_id'],
];
});
}
/** @return array{pool_id:int,next_member_id:int,queued:bool,blocked:bool} */
private static function selectAndQueueLocked(
int $poolId,
int $linkId,
?array $sync,
array $members,
string $today,
int $now
): array {
$selection = QywxPromotionWeightedRandom::select($members, $today, $now);
self::persistMemberCursors($selection['members'], $now);
$selectedId = (int) $selection['selected_id'];
if ($selectedId <= 0) {
self::upsertSync($poolId, $linkId, (int) ($sync['desired_member_id'] ?? 0), false, $sync, $now, '所有成员均已禁用、未生效或达到今日上限');
return ['pool_id' => $poolId, 'next_member_id' => 0, 'queued' => false, 'blocked' => true];
}
$changed = $selectedId !== (int) ($sync['desired_member_id'] ?? 0);
self::upsertSync($poolId, $linkId, $selectedId, $changed, $sync, $now);
return ['pool_id' => $poolId, 'next_member_id' => $selectedId, 'queued' => $changed, 'blocked' => false];
}
private static function upsertSync(
int $poolId,
int $linkId,
int $desiredMemberId,
bool $pending,
?array $existing,
int $now,
string $error = ''
): void {
$version = max(1, (int) ($existing['desired_version'] ?? 0) + ($pending ? 1 : 0));
$data = [
'promotion_link_id' => $linkId,
'desired_member_id' => $desiredMemberId,
'desired_version' => $version,
'status' => $error !== '' ? 4 : ($pending ? 1 : (int) ($existing['status'] ?? 0)),
'next_retry' => $error !== '' ? strtotime('tomorrow', $now) : ($pending ? $now : 0),
'last_error' => mb_substr($error, 0, 500),
'update_time' => $now,
];
if ($pending) {
$data['attempts'] = 0;
}
if ($existing) {
Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->update($data);
} else {
$data += [
'pool_id' => $poolId,
'applied_member_id' => 0,
'applied_version' => 0,
'attempts' => 0,
'lock_token' => '',
'lock_until' => 0,
'create_time' => $now,
];
Db::name('qywx_promotion_range_sync')->insert($data);
}
}
/** @return list<array<string,mixed>> */
private static function lockedMembers(int $poolId): array
{
return Db::name('qywx_promotion_pool_member')
->where('pool_id', $poolId)
->whereNull('delete_time')
->order('id', 'asc')
->lock(true)
->select()->toArray();
}
/** @return array<string,mixed>|null */
private static function lockedSyncRow(int $poolId): ?array
{
$row = Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->lock(true)->find();
return $row ?: null;
}
private static function promotionLinkId(int $poolId): int
{
$syncLinkId = (int) (Db::name('qywx_promotion_range_sync')
->where('pool_id', $poolId)->value('promotion_link_id') ?? 0);
if ($syncLinkId > 0) {
return $syncLinkId;
}
return (int) (Db::name('qywx_promotion_link')
->where('pool_id', $poolId)
->where('remote_link_id', '<>', '')
->where('remote_status', '<>', 2)
->whereNull('delete_time')
->order('id', 'desc')
->value('id') ?? 0);
}
/** @param list<array<string,mixed>> $members */
private static function persistMemberCursors(array $members, int $now): void
{
foreach ($members as $member) {
Db::name('qywx_promotion_pool_member')->where('id', (int) $member['id'])->update([
'current_weight' => (int) ($member['current_weight'] ?? 0),
'today_count' => max(0, (int) ($member['today_count'] ?? 0)),
'today_date' => (string) ($member['today_date'] ?? '') ?: null,
'total_count' => max(0, (int) ($member['total_count'] ?? 0)),
'last_assigned_time' => max(0, (int) ($member['last_assigned_time'] ?? 0)),
'update_time' => $now,
]);
}
}
}
@@ -0,0 +1,174 @@
<?php
declare(strict_types=1);
namespace app\common\service\qywx;
use RuntimeException;
use think\facade\Db;
/** 把回调调度出的单个目标成员同步到同一条企业微信官方获客链接。 */
class QywxPromotionRangeSyncService
{
private QywxCustomerAcquisitionApiService $api;
public function __construct(?QywxCustomerAcquisitionApiService $api = null)
{
$this->api = $api ?? new QywxCustomerAcquisitionApiService();
}
/** @return array{status:string,pool_id:int,member_id:int} */
public function syncPool(int $poolId): array
{
$claim = Db::transaction(function () use ($poolId): ?array {
$row = Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->lock(true)->find();
if (!$row) {
return null;
}
$status = (int) ($row['status'] ?? 0);
$now = time();
if ($status === 0 || $status === 4 || ($status === 2 && (int) ($row['lock_until'] ?? 0) > $now)) {
return null;
}
if ($status === 3 && (int) ($row['next_retry'] ?? 0) > $now) {
return null;
}
$token = bin2hex(random_bytes(16));
Db::name('qywx_promotion_range_sync')->where('pool_id', $poolId)->update([
'status' => 2,
'lock_token' => $token,
'lock_until' => $now + 90,
'attempts' => (int) ($row['attempts'] ?? 0) + 1,
'last_error' => '',
'update_time' => $now,
]);
$row['lock_token'] = $token;
return $row;
});
if ($claim === null) {
return ['status' => 'noop', 'pool_id' => $poolId, 'member_id' => 0];
}
$token = (string) $claim['lock_token'];
$desiredVersion = (int) ($claim['desired_version'] ?? 0);
$memberId = (int) ($claim['desired_member_id'] ?? 0);
try {
$pool = Db::name('qywx_promotion_pool')->where('id', $poolId)->whereNull('delete_time')->find();
$link = Db::name('qywx_promotion_link')
->where('id', (int) ($claim['promotion_link_id'] ?? 0))
->whereNull('delete_time')->find();
$member = Db::name('qywx_promotion_pool_member')
->where('id', $memberId)->where('pool_id', $poolId)->whereNull('delete_time')->find();
if (!$pool || !$link || !$member || (int) ($member['enabled'] ?? 0) !== 1) {
throw new RuntimeException('分流方案、官方链接或目标成员已失效');
}
$remoteLinkId = trim((string) ($link['remote_link_id'] ?? ''));
$userId = trim((string) ($member['userid'] ?? ''));
if ($remoteLinkId === '' || $userId === '') {
throw new RuntimeException('官方链接 ID 或目标成员 userid 为空');
}
$this->api->updateLink([
'link_id' => $remoteLinkId,
'link_name' => mb_substr((string) ($pool['name'] ?? '获客分流方案'), 0, 30),
'range' => ['user_list' => [$userId]],
'skip_verify' => (int) ($link['skip_verify'] ?? 0) === 1,
]);
$response = $this->api->getLink($remoteLinkId);
$remote = QywxCustomerAcquisitionLinkService::normaliseRemoteResponse($response, $remoteLinkId);
$actualUserIds = $remote['range_userids'];
if ($actualUserIds !== [$userId]) {
throw new RuntimeException('企业微信返回的成员范围与待同步成员不一致');
}
$url = $remote['url'];
$snapshot = json_encode($remote['snapshot'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
Db::name('qywx_promotion_link')->where('id', (int) $link['id'])->update([
'wecom_url' => $url,
'remote_status' => 1,
'range_user_json' => json_encode($actualUserIds, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'range_department_json' => json_encode($remote['range_department_ids'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'remote_snapshot' => $snapshot === false ? null : $snapshot,
'last_sync_time' => time(),
'sync_error' => '',
'update_time' => time(),
]);
$freshVersion = (int) (Db::name('qywx_promotion_range_sync')
->where('pool_id', $poolId)->value('desired_version') ?? 0);
Db::name('qywx_promotion_range_sync')
->where('pool_id', $poolId)
->where('lock_token', $token)
->update([
'status' => $freshVersion === $desiredVersion ? 0 : 1,
'applied_member_id' => $memberId,
'applied_version' => $desiredVersion,
'next_retry' => $freshVersion === $desiredVersion ? 0 : time(),
'attempts' => 0,
'lock_token' => '',
'lock_until' => 0,
'last_error' => '',
'update_time' => time(),
]);
return ['status' => 'synced', 'pool_id' => $poolId, 'member_id' => $memberId];
} catch (\Throwable $e) {
$attempts = max(1, (int) ($claim['attempts'] ?? 0) + 1);
Db::name('qywx_promotion_range_sync')
->where('pool_id', $poolId)
->where('lock_token', $token)
->update([
'status' => 3,
'next_retry' => time() + min(300, 15 * $attempts),
'lock_token' => '',
'lock_until' => 0,
'last_error' => mb_substr($e->getMessage(), 0, 500),
'update_time' => time(),
]);
Db::name('qywx_promotion_link')
->where('id', (int) ($claim['promotion_link_id'] ?? 0))
->update(['sync_error' => mb_substr($e->getMessage(), 0, 500), 'update_time' => time()]);
throw $e;
}
}
/** @return array{selected:int,synced:int,failed:int} */
public function syncPending(int $limit = 100): array
{
$now = time();
$blockedPoolIds = Db::name('qywx_promotion_range_sync')
->where('status', 4)
->where('next_retry', '>', 0)
->where('next_retry', '<=', $now)
->limit(min(500, max(1, $limit)))
->column('pool_id');
foreach ($blockedPoolIds as $blockedPoolId) {
QywxPromotionMemberSchedulerService::reconcilePool((int) $blockedPoolId);
}
$poolIds = Db::name('qywx_promotion_range_sync')
->where(function ($query) use ($now): void {
$query->whereIn('status', [1, 3])->where('next_retry', '<=', $now)
->whereOr(function ($running) use ($now): void {
$running->where('status', 2)->where('lock_until', '<=', $now);
});
})
->order('next_retry', 'asc')
->limit(min(500, max(1, $limit)))
->column('pool_id');
$synced = 0;
$failed = 0;
foreach ($poolIds as $poolId) {
try {
$result = $this->syncPool((int) $poolId);
if ($result['status'] === 'synced') {
$synced++;
}
} catch (\Throwable) {
$failed++;
}
}
return ['selected' => count($poolIds), 'synced' => $synced, 'failed' => $failed];
}
}
@@ -6,10 +6,10 @@ namespace app\common\service\qywx;
use think\facade\Db;
/** 公开获客助手链接分流:按权重随机,并在事务内维护当日限额与点击计数。 */
/** 公开获客助手链接:新方案直达单个官方链接,旧 /go 入口继续兼容历史分流。 */
class QywxPromotionRedirectService
{
/** @return array{status:int,widget_config_json:?string}|null */
/** @return array{status:int,widget_config_json:?string,target_url:string}|null */
public static function publicPoolConfig(string $publicKey): ?array
{
if (preg_match('/^[a-f0-9]{32}$/', $publicKey) !== 1) {
@@ -19,17 +19,32 @@ class QywxPromotionRedirectService
$row = Db::name('qywx_promotion_pool')
->where('public_key', $publicKey)
->whereNull('delete_time')
->field('status,widget_config_json')
->field('id,status,widget_config_json')
->find();
if (!$row) {
return null;
}
$link = Db::name('qywx_promotion_link')
->where('pool_id', (int) $row['id'])
->where('status', 1)
->where('remote_status', 1)
->where('remote_link_id', '<>', '')
->whereNull('delete_time')
->order('id', 'desc')
->field('wecom_url')
->find();
$targetUrl = QywxCustomerAcquisitionLinkService::withCustomerChannel(
(string) ($link['wecom_url'] ?? ''),
'zyt_pool:' . (int) $row['id']
);
return [
'status' => (int) ($row['status'] ?? 0),
'widget_config_json' => isset($row['widget_config_json'])
? (string) $row['widget_config_json']
: null,
'target_url' => $targetUrl,
];
}
@@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace app\common\service\qywx;
use InvalidArgumentException;
/** 获客方案成员的加权随机选择;数据库锁与持久化由调度服务负责。 */
class QywxPromotionWeightedRandom
{
/**
* @param list<array<string,mixed>> $members
* @param int|null $draw 测试用固定抽签值;生产环境留空并使用 random_int。
* @return array{selected_id:int,members:list<array<string,mixed>>,eligible_count:int,total_weight:int}
*/
public static function select(array $members, string $today, int $now, ?int $draw = null): array
{
$eligibleIndexes = [];
$totalWeight = 0;
foreach ($members as $index => &$member) {
if ((string) ($member['today_date'] ?? '') !== $today) {
$member['today_date'] = $today;
$member['today_count'] = 0;
}
// current_weight 是旧版平滑轮询游标;随机模式不再使用,统一归零。
$member['current_weight'] = 0;
if (!self::eligible($member, $now)) {
continue;
}
$weight = max(1, (int) ($member['weight'] ?? 1));
$eligibleIndexes[] = ['index' => $index, 'weight' => $weight];
$totalWeight += $weight;
}
unset($member);
if ($eligibleIndexes === []) {
return [
'selected_id' => 0,
'members' => array_values($members),
'eligible_count' => 0,
'total_weight' => 0,
];
}
$ticket = $draw ?? random_int(1, $totalWeight);
if ($ticket < 1 || $ticket > $totalWeight) {
throw new InvalidArgumentException('加权随机抽签值超出有效范围');
}
$cursor = 0;
$selectedIndex = (int) $eligibleIndexes[0]['index'];
foreach ($eligibleIndexes as $candidate) {
$cursor += (int) $candidate['weight'];
if ($ticket <= $cursor) {
$selectedIndex = (int) $candidate['index'];
break;
}
}
return [
'selected_id' => (int) ($members[$selectedIndex]['id'] ?? 0),
'members' => array_values($members),
'eligible_count' => count($eligibleIndexes),
'total_weight' => $totalWeight,
];
}
/** @param array<string,mixed> $member */
public static function eligible(array $member, int $now): bool
{
if ((int) ($member['enabled'] ?? 0) !== 1 || (int) ($member['weight'] ?? 0) <= 0) {
return false;
}
$start = max(0, (int) ($member['active_start'] ?? 0));
$end = max(0, (int) ($member['active_end'] ?? 0));
if (($start > 0 && $start > $now) || ($end > 0 && $end < $now)) {
return false;
}
$limit = max(0, (int) ($member['daily_limit'] ?? 0));
return $limit === 0 || (int) ($member['today_count'] ?? 0) < $limit;
}
}
@@ -131,11 +131,11 @@ class QywxPromotionWidgetService
}
/**
* 生成可直接跨站安装的完整脚本。真实获客链接始终只由跳转端点选择
* 生成可直接跨站安装的完整脚本,点击后直达当前方案的企业微信官方链接
*
* @param array<string, mixed> $config
*/
public static function renderScript(string $key, string $goUrl, array $config, bool $poolEnabled = true): string
public static function renderScript(string $key, string $targetUrl, array $config, bool $poolEnabled = true): string
{
$config = self::fromInput($config);
if (!$poolEnabled) {
@@ -143,14 +143,14 @@ class QywxPromotionWidgetService
}
$jsonKey = self::jsonForScript($key);
$jsonGo = self::jsonForScript($goUrl);
$jsonTarget = self::jsonForScript($targetUrl);
$jsonConfig = self::jsonForScript($config);
return <<<JS
(function(w,d){
'use strict';
var key={$jsonKey},goPath={$jsonGo},config={$jsonConfig},scriptNode=d.currentScript||null;
var go=resolveGoUrl(goPath);
var key={$jsonKey},targetPath={$jsonTarget},config={$jsonConfig},scriptNode=d.currentScript||null;
var targetUrl=resolveTargetUrl(targetPath);
var registry=w.WecomPromotion=w.WecomPromotion||{};
var previous=registry[key];
if(previous&&previous.__widgetVersion===1&&typeof previous.destroy==='function'){
@@ -170,7 +170,7 @@ class QywxPromotionWidgetService
return null;
}
function resolveGoUrl(value){
function resolveTargetUrl(value){
if(/^https?:\/\//i.test(value)){return value;}
var node=findScriptNode();
if(node&&node.src&&typeof w.URL==='function'){
@@ -179,14 +179,8 @@ class QywxPromotionWidgetService
return value;
}
function sourceUrl(){
var location=w.location||{};
var origin=location.origin||((location.protocol&&location.host)?location.protocol+'//'+location.host:'');
return origin+(location.pathname||'/');
}
function openPromotion(){
w.location.assign(go+'?from='+encodeURIComponent(sourceUrl()));
if(targetUrl){w.location.assign(targetUrl);}
}
function handleDocumentClick(event){
+4 -2
View File
@@ -30,8 +30,10 @@ return [
'qywx:scan-media-channel' => 'app\\command\\QywxScanMediaChannel',
// 企业微信会话内容存档同步(需开通会话存档 License 并配置 msgaudit_* 相关项 + 动态库)
'qywx:sync-msg-archive' => 'app\\command\\QywxSyncMsgArchive',
// 获客助手 ChatKey 仅 30 分钟有效,部署时应每分钟执行一次
'qywx:retry-customer-acquisition-events' => 'app\\command\\QywxRetryCustomerAcquisitionEvents',
// 获客助手 ChatKey 仅 30 分钟有效,部署时应每分钟执行一次
'qywx:retry-customer-acquisition-events' => 'app\\command\\QywxRetryCustomerAcquisitionEvents',
// 回调确认实际承接成员后,按权重/上限切换同一条官方获客链接的成员范围
'qywx:sync-promotion-ranges' => 'app\\command\\QywxSyncPromotionRanges',
// 甘草订单物流路由同步(GET_TASK_ROUTE_LIST
'gancao:sync-logistics' => 'app\\command\\GancaoSyncLogisticsRoute',
'ej-pharmacy:sync-catalog' => 'app\\command\\EjPharmacySyncCatalog',
+43 -13
View File
@@ -30,19 +30,51 @@ HOST = "https://公开访问域名"
- 更新获客链接 `update_link`
- 删除获客链接 `delete_link`
“永久删除企业微信链接”会调用官方删除接口且无法恢复;“从本地移除”只退出当前分流池,不会修改企业微信后台
当前管理端按“一个分流方案对应一个官方获客链接”管理。删除分流方案只软删除本地记录,不调用企业微信 `delete_link`,因此不会破坏已有客户归因;官方永久删除接口仅保留给兼容接口使用,调用后无法恢复
获客成员来自后台管理员的 `work_wechat_userid`。管理员可管理全量;组长、医助等账号只返回 `DataScopeService` 当前角色与部门范围内的成员。同步远端链接时,非全量账号只导入 `range.user_list` 与其可见成员有交集的数据;企业微信部门 ID 尚未建立本地映射时按安全原则隐藏,不会越权放行。
`list_link` 只返回当前获客助手可调用应用通过 API 创建的官方链接。后台历史手工粘贴的 `work.weixin.qq.com/ca/...` 链接,以及其他应用创建的链接,不会出现在当前应用的同步列表中,也无法仅凭 URL 反查为官方 `link_id`。需要官方客户、统计和消息归因时,应在本页面使用“创建官方获客链接”
`list_link` 只返回当前获客助手可调用应用通过 API 创建的官方链接。后台历史手工粘贴的 `work.weixin.qq.com/ca/...` 链接,以及其他应用创建的链接,不会出现在当前应用的同步列表中,也无法仅凭 URL 反查为官方 `link_id`。需要官方客户、统计和消息归因时,应在本页面创建分流方案并选择获客成员
链接分流只接受企业微信获客助手生成的链接:
创建分流方案时必须选择一名或多名医助。所有医助分别保存启用状态、权重、每日上限、有效时间和实际获客计数,但一个方案仍只创建一条企业微信官方链接。官方链接当前的 `range.user_list` 只放调度器选中的一名成员,回调确认实际承接结果后再按权重随机抽取下一名并更新同一个 `link_id`,因此对外 URL 始终不变。
新建方案时的首名成员也会从所选医助中随机产生;编辑已有方案时,如果当前成员仍可用则保持不变,避免无获客事件时无故切换。
系统只使用企业微信获客助手生成的链接:
```text
https://work.weixin.qq.com/ca/xxxxxxxx
```
“联系我”、客户群、自有网页或其他外部链接均会被拒绝;已有的非获客助手历史链接不会参与随机分流。Secret 与 access_token 不会返回到浏览器,也不会写入接口错误日志。
“联系我”、客户群、自有网页或其他外部链接均会被拒绝;已有的非获客助手历史链接不会作为方案主链接。Secret 与 access_token 不会返回到浏览器,也不会写入接口错误日志。
可复制的主链接会追加分流方案渠道参数,结构如下:
```text
https://work.weixin.qq.com/ca/xxxxxxxx?customer_channel=zyt_pool:123
```
其中 `customer_channel` 是本站写入的自定义渠道值,格式为 `zyt_pool:分流方案ID`;它与示例中的 `qywx_ca:...` 作用相同,但命名空间和数值由各系统自行定义。
## 回调驱动成员调度
部署时必须执行:
```text
server/sql/1.9.20260824/upgrade_qywx_promotion_member_dispatch.sql
```
并在企业微信后台把“API 接收消息”配置为:
```text
https://你的域名/api/qywx/external-contact/notify
```
调度优先使用 `change_external_contact/add_external_contact` 事件中的 `State``UserID``ExternalUserID``State` 来自主链接的 `customer_channel=zyt_pool:方案ID`,因此可以定位方案及实际承接医助;获客会话回调会通过 `ChatKey → get_chat_info` 作为补偿。方案、成员和客户组合使用唯一幂等键,同一实际获客不会因重复回调重复计数。
每次确认实际承接后,系统执行加权随机抽取:权重越大,被抽中的概率越高;禁用、尚未生效、已过期或达到今日上限的成员不会进入随机池。随机允许连续抽中同一成员。待同步范围由 `qywx:sync-promotion-ranges` 每分钟重试,管理端主动禁用当前成员时也会立即尝试同步。
权重和数量属于回调驱动的近实时控制,并非点击前的强事务:多个客户在企微回调或 `update_link` 生效前并发访问时,可能仍由同一成员承接;所有成员都达到上限时,企业微信不允许把 `range.user_list` 更新为空,系统会标记“无可用成员”并保留最后一次有效范围。因此数量上限用于自动退出后续调度,不承诺并发场景下绝对零超量。
如果需要为点击 IP 生成不可逆服务端哈希,可在 `[qywx_promotion]` 下额外设置独立的 `CREDENTIAL_KEY`
@@ -50,9 +82,11 @@ https://work.weixin.qq.com/ca/xxxxxxxx
```html
<script src="https://你的域名/api/qywx-promotion/js/分流方案KEY" defer></script>
<a href="https://你的域名/api/qywx-promotion/go/分流方案KEY" data-wecom-promotion="分流方案KEY">添加企业微信</a>
<a href="https://work.weixin.qq.com/ca/xxxxxxxx?customer_channel=zyt_pool:123">添加企业微信</a>
```
旧的 `/api/qywx-promotion/go/分流方案KEY` 地址继续保留,兼容已经投放的安装代码;新建方案、管理端复制链接和新版浮窗均直接打开官方获客链接。
## 公开浮窗
每个分流方案可选择是否由同一段公开 JS 自动挂载客服浮窗。关闭浮窗时,已有的
@@ -66,7 +100,7 @@ https://work.weixin.qq.com/ca/xxxxxxxx
- 标题、副标题、按钮文案和 `#RRGGBB` 主题色
- 16-160 像素底部距离、移动端展示开关和浮窗总开关
公开脚本仅下发经过白名单校验的展示配置,不下发兜底链接或真实获客链接池。模板
公开脚本仅下发经过白名单校验的展示配置和当前方案的单个官方目标链接,不下发历史链接池或 Secret。模板
由脚本内置,管理端文案通过 DOM `textContent` 写入,不接受自定义 HTML、CSS 或脚本。
损坏配置、未知版本和非法枚举会按关闭浮窗处理。
@@ -79,10 +113,7 @@ window.WecomPromotion['分流方案KEY'].hide()
window.WecomPromotion['分流方案KEY'].destroy()
```
公开脚本缓存 60 秒,因此浮窗样式开关更新最多延迟约 60 秒;方案运行状态仍会在
每次服务端跳转时即时校验。脚本会从自身 `src` 解析跳转接口域名,不会把公开请求的
Host 写入缓存内容。管理端安装代码优先使用 `[app] HOST`,请在生产环境配置唯一的
HTTPS 公开域名。
公开脚本缓存 60 秒,因此浮窗样式开关或官方目标链接更新最多延迟约 60 秒。新版浮窗直接打开企业微信官方链接,不再经过本站逐次 302;已经复制到外部的官方链接也不会因本地关闭方案而失效。管理端安装代码优先使用 `[app] HOST`,请在生产环境配置唯一的 HTTPS 公开域名。
接入站点若启用了严格 CSP,需要允许脚本域名,并给安装 `<script>` 添加站点当前请求
`nonce`。公开脚本会把该 `nonce` 传给 Shadow DOM 内的动态样式:
@@ -91,7 +122,6 @@ HTTPS 公开域名。
<script nonce="当前请求的 nonce" src="https://你的域名/api/qywx-promotion/js/分流方案KEY" defer></script>
```
点击来源只上报页面的 origin 与 pathname,不包含查询参数或 fragment。推广页路径中也
不应放置手机号、患者 ID、重置令牌等敏感信息。
`/go` 兼容入口记录点击来源时,只保存页面的 origin 与 pathname,不包含查询参数或 fragment。推广页路径中也不应放置手机号、患者 ID、重置令牌等敏感信息。
随机分流在服务端完成。候选链接必须同时满足:方案启用、链接上线、处于有效时间段、未超过当日上限。权重越大,被选中的概率越高
用户始终看到同一个企业微信官方获客链接。当前激活成员由本站根据实际回调、启用状态、权重和上限动态更新;企业微信仍可能根据成员可服务状态和已有好友关系等规则影响最终承接结果,后续回调会按实际结果自动纠偏
@@ -1 +1 @@
import t from"./error-DGH5hr-_.js";import{o,q as r,r as a,v as n,D as c,s}from"./.pnpm-Dwh6tNxD.js";import"./index-C9ilrjDr.js";const p="/admin/assets/no_perms-jDxcYpYC.png",i={class:"error404"},x=o({__name:"403",setup(m){return(_,e)=>(r(),a("div",i,[n(t,{code:"403",title:"您的账号权限不足,请联系管理员添加权限!","show-btn":!1},{content:c(()=>[...e[0]||(e[0]=[s("div",{class:"flex justify-center"},[s("img",{class:"w-[150px] h-[150px]",src:p,alt:""})],-1)])]),_:1})]))}});export{x as default};
import t from"./error-BSPt5W5D.js";import{o,q as r,r as a,v as n,D as c,s}from"./.pnpm-Dwh6tNxD.js";import"./index-C0Q8AuuZ.js";const p="/admin/assets/no_perms-jDxcYpYC.png",i={class:"error404"},x=o({__name:"403",setup(m){return(_,e)=>(r(),a("div",i,[n(t,{code:"403",title:"您的账号权限不足,请联系管理员添加权限!","show-btn":!1},{content:c(()=>[...e[0]||(e[0]=[s("div",{class:"flex justify-center"},[s("img",{class:"w-[150px] h-[150px]",src:p,alt:""})],-1)])]),_:1})]))}});export{x as default};
@@ -1 +1 @@
import e from"./error-DGH5hr-_.js";import{o,q as r,r as t,v as s}from"./.pnpm-Dwh6tNxD.js";import"./index-C9ilrjDr.js";const a={class:"error404"},d=o({__name:"404",setup(c){return(n,_)=>(r(),t("div",a,[s(e,{code:"404",title:"哎呀,出错了!您访问的页面不存在…"})]))}});export{d as default};
import e from"./error-BSPt5W5D.js";import{o,q as r,r as t,v as s}from"./.pnpm-Dwh6tNxD.js";import"./index-C0Q8AuuZ.js";const a={class:"error404"},d=o({__name:"404",setup(c){return(n,_)=>(r(),t("div",a,[s(e,{code:"404",title:"哎呀,出错了!您访问的页面不存在…"})]))}});export{d as default};
@@ -1 +1 @@
import{o as C,R as D,q as d,r as I,ac as N,O as u,bj as B,D as o,v as l,bk as E,br as L,L as i,T as r,s as p,bi as R,M as w}from"./.pnpm-Dwh6tNxD.js";import{a as V}from"./doctor-DZ47WohD.js";import{m as A,_ as M}from"./index-C9ilrjDr.js";const P={class:"appointment-record-panel"},$={class:"cell-stack"},j={class:"font-medium"},q={class:"text-gray-500 text-sm"},O={class:"cell-stack"},F={class:"text-gray-500 text-sm"},G=C({__name:"AppointmentRecordPanel",props:{diagnosisId:{}},setup(v,{expose:y}){const f=v,m=w(!1),g=w([]),h=w({});function x(t){return t?String(t).length>=8?String(t).slice(0,5):t:""}function k(t){return t==="morning"?"上午":t==="afternoon"?"下午":t==="all"?"全天":t||"—"}function S(t){const n=t.channel_source??t.channels??"";if(n===""||n===null||n===void 0)return"—";const a=String(n),s=h.value[a]||a,c=String(t.channel_source_detail??"").trim();return c!==""?`${s}${c}`:s}function T(t){return[...t].sort((n,a)=>{const s=String(n.appointment_date||""),c=String(a.appointment_date||"");if(s!==c)return c.localeCompare(s);const _=String(n.appointment_time||""),e=String(a.appointment_time||"");return _!==e?e.localeCompare(_):Number(a.id||0)-Number(n.id||0)})}const z=async()=>{try{const t=await A({type:"channels"}),n=((t==null?void 0:t.channels)||[]).filter(s=>s.status!==0),a={};for(const s of n)s.value!=null&&(a[String(s.value)]=s.name||String(s.value));h.value=a}catch{h.value={}}},b=async()=>{if(f.diagnosisId){m.value=!0;try{await z();const t=await V({patient_id:f.diagnosisId,diag_scope_relax:1,page_no:1,page_size:500}),n=(t==null?void 0:t.lists)||[];g.value=T(n)}catch(t){console.error(t),g.value=[]}finally{m.value=!1}}};return D(()=>f.diagnosisId,()=>{b()},{immediate:!0}),y({refresh:b}),(t,n)=>{const a=E,s=L,c=B,_=R;return d(),I("div",P,[N((d(),u(c,{data:g.value,border:"",stripe:"","empty-text":"暂无挂号记录"},{default:o(()=>[l(a,{label:"ID",prop:"id",width:"72",align:"center"}),l(a,{label:"状态",width:"100",align:"center"},{default:o(({row:e})=>[l(s,{type:e.status===1?"success":e.status===2?"info":e.status===3?"primary":"danger",size:"small",effect:"light"},{default:o(()=>[i(r(e.status_desc||"—"),1)]),_:2},1032,["type"])]),_:1}),l(a,{label:"患者(挂号人)","min-width":"150"},{default:o(({row:e})=>[p("div",$,[p("span",j,r(e.patient_name||"—"),1),p("span",q,r(e.patient_phone||""),1)])]),_:1}),l(a,{label:"挂号医生",prop:"doctor_name",width:"110","show-overflow-tooltip":""}),l(a,{label:"挂号助理",width:"110","show-overflow-tooltip":""},{default:o(({row:e})=>[i(r(e.assistant_name||"—"),1)]),_:1}),l(a,{label:"预约时间","min-width":"130"},{default:o(({row:e})=>[p("div",O,[p("span",null,r(e.appointment_date||"—"),1),p("span",F,r(x(e.appointment_time)),1)])]),_:1}),l(a,{label:"时段",width:"80",align:"center"},{default:o(({row:e})=>[i(r(k(e.period)),1)]),_:1}),l(a,{label:"类型",width:"100","show-overflow-tooltip":""},{default:o(({row:e})=>[i(r(e.appointment_type_desc||"—"),1)]),_:1}),l(a,{label:"渠道",width:"110","show-overflow-tooltip":""},{default:o(({row:e})=>[i(r(S(e)),1)]),_:1}),l(a,{label:"确认诊单",width:"92",align:"center"},{default:o(({row:e})=>[e.diagnosis_confirmed?(d(),u(s,{key:0,type:"success",size:"small",effect:"plain"},{default:o(()=>[...n[0]||(n[0]=[i("已确认",-1)])]),_:1})):(d(),u(s,{key:1,type:"warning",size:"small",effect:"plain"},{default:o(()=>[...n[1]||(n[1]=[i("未确认",-1)])]),_:1}))]),_:1}),l(a,{label:"开方",width:"80",align:"center"},{default:o(({row:e})=>[e.has_prescription?(d(),u(s,{key:0,type:"success",size:"small",effect:"plain"},{default:o(()=>[...n[2]||(n[2]=[i("已开方",-1)])]),_:1})):(d(),u(s,{key:1,type:"info",size:"small",effect:"plain"},{default:o(()=>[...n[3]||(n[3]=[i("未开方",-1)])]),_:1}))]),_:1}),l(a,{label:"备注",prop:"remark","min-width":"100","show-overflow-tooltip":""}),l(a,{label:"创建时间",width:"165",prop:"create_time"})]),_:1},8,["data"])),[[_,m.value]])])}}}),Q=M(G,[["__scopeId","data-v-4de87dfa"]]);export{Q as default};
import{o as C,R as D,q as d,r as I,ac as N,O as u,bj as B,D as o,v as l,bk as E,br as L,L as i,T as r,s as p,bi as R,M as w}from"./.pnpm-Dwh6tNxD.js";import{a as V}from"./doctor-CTRg8la2.js";import{m as A,_ as M}from"./index-C0Q8AuuZ.js";const P={class:"appointment-record-panel"},$={class:"cell-stack"},j={class:"font-medium"},q={class:"text-gray-500 text-sm"},O={class:"cell-stack"},F={class:"text-gray-500 text-sm"},G=C({__name:"AppointmentRecordPanel",props:{diagnosisId:{}},setup(v,{expose:y}){const f=v,m=w(!1),g=w([]),h=w({});function x(t){return t?String(t).length>=8?String(t).slice(0,5):t:""}function k(t){return t==="morning"?"上午":t==="afternoon"?"下午":t==="all"?"全天":t||"—"}function S(t){const n=t.channel_source??t.channels??"";if(n===""||n===null||n===void 0)return"—";const a=String(n),s=h.value[a]||a,c=String(t.channel_source_detail??"").trim();return c!==""?`${s}${c}`:s}function T(t){return[...t].sort((n,a)=>{const s=String(n.appointment_date||""),c=String(a.appointment_date||"");if(s!==c)return c.localeCompare(s);const _=String(n.appointment_time||""),e=String(a.appointment_time||"");return _!==e?e.localeCompare(_):Number(a.id||0)-Number(n.id||0)})}const z=async()=>{try{const t=await A({type:"channels"}),n=((t==null?void 0:t.channels)||[]).filter(s=>s.status!==0),a={};for(const s of n)s.value!=null&&(a[String(s.value)]=s.name||String(s.value));h.value=a}catch{h.value={}}},b=async()=>{if(f.diagnosisId){m.value=!0;try{await z();const t=await V({patient_id:f.diagnosisId,diag_scope_relax:1,page_no:1,page_size:500}),n=(t==null?void 0:t.lists)||[];g.value=T(n)}catch(t){console.error(t),g.value=[]}finally{m.value=!1}}};return D(()=>f.diagnosisId,()=>{b()},{immediate:!0}),y({refresh:b}),(t,n)=>{const a=E,s=L,c=B,_=R;return d(),I("div",P,[N((d(),u(c,{data:g.value,border:"",stripe:"","empty-text":"暂无挂号记录"},{default:o(()=>[l(a,{label:"ID",prop:"id",width:"72",align:"center"}),l(a,{label:"状态",width:"100",align:"center"},{default:o(({row:e})=>[l(s,{type:e.status===1?"success":e.status===2?"info":e.status===3?"primary":"danger",size:"small",effect:"light"},{default:o(()=>[i(r(e.status_desc||"—"),1)]),_:2},1032,["type"])]),_:1}),l(a,{label:"患者(挂号人)","min-width":"150"},{default:o(({row:e})=>[p("div",$,[p("span",j,r(e.patient_name||"—"),1),p("span",q,r(e.patient_phone||""),1)])]),_:1}),l(a,{label:"挂号医生",prop:"doctor_name",width:"110","show-overflow-tooltip":""}),l(a,{label:"挂号助理",width:"110","show-overflow-tooltip":""},{default:o(({row:e})=>[i(r(e.assistant_name||"—"),1)]),_:1}),l(a,{label:"预约时间","min-width":"130"},{default:o(({row:e})=>[p("div",O,[p("span",null,r(e.appointment_date||"—"),1),p("span",F,r(x(e.appointment_time)),1)])]),_:1}),l(a,{label:"时段",width:"80",align:"center"},{default:o(({row:e})=>[i(r(k(e.period)),1)]),_:1}),l(a,{label:"类型",width:"100","show-overflow-tooltip":""},{default:o(({row:e})=>[i(r(e.appointment_type_desc||"—"),1)]),_:1}),l(a,{label:"渠道",width:"110","show-overflow-tooltip":""},{default:o(({row:e})=>[i(r(S(e)),1)]),_:1}),l(a,{label:"确认诊单",width:"92",align:"center"},{default:o(({row:e})=>[e.diagnosis_confirmed?(d(),u(s,{key:0,type:"success",size:"small",effect:"plain"},{default:o(()=>[...n[0]||(n[0]=[i("已确认",-1)])]),_:1})):(d(),u(s,{key:1,type:"warning",size:"small",effect:"plain"},{default:o(()=>[...n[1]||(n[1]=[i("未确认",-1)])]),_:1}))]),_:1}),l(a,{label:"开方",width:"80",align:"center"},{default:o(({row:e})=>[e.has_prescription?(d(),u(s,{key:0,type:"success",size:"small",effect:"plain"},{default:o(()=>[...n[2]||(n[2]=[i("已开方",-1)])]),_:1})):(d(),u(s,{key:1,type:"info",size:"small",effect:"plain"},{default:o(()=>[...n[3]||(n[3]=[i("未开方",-1)])]),_:1}))]),_:1}),l(a,{label:"备注",prop:"remark","min-width":"100","show-overflow-tooltip":""}),l(a,{label:"创建时间",width:"165",prop:"create_time"})]),_:1},8,["data"])),[[_,m.value]])])}}}),Q=M(G,[["__scopeId","data-v-4de87dfa"]]);export{Q as default};
@@ -1 +1 @@
import{o as T,R as C,q as _,r as b,ac as D,O as h,bj as $,D as r,v as n,bk as L,L as c,T as d,br as k,s as E,a1 as A,w as P,u as B,ch as F,bi as M,M as w}from"./.pnpm-Dwh6tNxD.js";import{ae as V}from"./tcm-RVDaIW5j.js";import{_ as q}from"./index-C9ilrjDr.js";const K={class:"assign-log-panel"},j={key:1,class:"text-gray-400"},z=T({__name:"AssignLogPanel",props:{diagnosisId:{}},setup(v,{expose:y}){const u=v,m=w(!1),p=w([]);function N(a){const e=a.related_po_creator_name;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(a.related_po_creator_id);return Number.isFinite(t)&&t>0?`ID:${t}`:"—"}function x(a){const e=a.related_po_create_time_text;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(a.related_po_create_time);if(!Number.isFinite(t)||t<=0)return"—";const s=new Date(t*1e3);if(Number.isNaN(s.getTime()))return"—";const o=l=>String(l).padStart(2,"0");return`${s.getFullYear()}-${o(s.getMonth()+1)}-${o(s.getDate())} ${o(s.getHours())}:${o(s.getMinutes())}:${o(s.getSeconds())}`}function f(a,e){const t=e==="from"?"from_assistant_name":"to_assistant_name",s=e==="from"?"from_assistant_id":"to_assistant_id",o=a[t];if(o!=null&&String(o).trim()!==""&&String(o)!=="—")return String(o);const l=Number(a[s]);return Number.isFinite(l)&&l>0?`ID:${l}`:"—"}const g=async()=>{if(u.diagnosisId){m.value=!0;try{const a=await V({id:u.diagnosisId}),e=Array.isArray(a)?a:[];p.value=e}catch(a){console.error(a),p.value=[]}finally{m.value=!1}}};return C(()=>u.diagnosisId,()=>{g()},{immediate:!0}),y({refresh:g}),(a,e)=>{const t=L,s=k,o=P,l=A,S=$,I=M;return _(),b("div",K,[D((_(),h(S,{data:p.value,border:"",stripe:"","empty-text":"暂无指派记录"},{default:r(()=>[n(t,{label:"操作时间",width:"175",prop:"create_time_text"}),n(t,{label:"原医助","min-width":"120"},{default:r(({row:i})=>[c(d(f(i,"from")),1)]),_:1}),n(t,{label:"新医助","min-width":"120"},{default:r(({row:i})=>[c(d(f(i,"to")),1)]),_:1}),n(t,{label:"继承",width:"72",align:"center"},{default:r(({row:i})=>[Number(i.is_inherit)===1?(_(),h(s,{key:0,type:"success",size:"small"},{default:r(()=>[...e[0]||(e[0]=[c("是",-1)])]),_:1})):(_(),b("span",j,"否"))]),_:1}),n(t,{label:"快照·业务单创建人","min-width":"130","show-overflow-tooltip":""},{default:r(({row:i})=>[c(d(N(i)),1)]),_:1}),n(t,{label:"快照·业务单创建时间",width:"190"},{header:r(()=>[e[1]||(e[1]=E("span",null,"快照·业务单创建时间",-1)),n(l,{placement:"top",content:"related_po_create_time:触发本次操作的处方业务订单 create_time;与原文助一致时表示医助创建订单时间"},{default:r(()=>[n(o,{class:"assign-log-col-hint"},{default:r(()=>[n(B(F))]),_:1})]),_:1})]),default:r(({row:i})=>[c(d(x(i)),1)]),_:1}),n(t,{label:"操作人",width:"110",prop:"operator_name"}),n(t,{label:"操作账号",width:"120",prop:"operator_account","show-overflow-tooltip":""}),n(t,{label:"IP",width:"130",prop:"ip","show-overflow-tooltip":""})]),_:1},8,["data"])),[[I,m.value]])])}}}),Y=q(z,[["__scopeId","data-v-f670e3e6"]]);export{Y as default};
import{o as T,R as C,q as _,r as b,ac as D,O as h,bj as $,D as r,v as n,bk as L,L as c,T as d,br as k,s as E,a1 as A,w as P,u as B,ch as F,bi as M,M as w}from"./.pnpm-Dwh6tNxD.js";import{ae as V}from"./tcm-WWBqr2Vo.js";import{_ as q}from"./index-C0Q8AuuZ.js";const K={class:"assign-log-panel"},j={key:1,class:"text-gray-400"},z=T({__name:"AssignLogPanel",props:{diagnosisId:{}},setup(v,{expose:y}){const u=v,m=w(!1),p=w([]);function N(a){const e=a.related_po_creator_name;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(a.related_po_creator_id);return Number.isFinite(t)&&t>0?`ID:${t}`:"—"}function x(a){const e=a.related_po_create_time_text;if(e!=null&&String(e).trim()!=="")return String(e);const t=Number(a.related_po_create_time);if(!Number.isFinite(t)||t<=0)return"—";const s=new Date(t*1e3);if(Number.isNaN(s.getTime()))return"—";const o=l=>String(l).padStart(2,"0");return`${s.getFullYear()}-${o(s.getMonth()+1)}-${o(s.getDate())} ${o(s.getHours())}:${o(s.getMinutes())}:${o(s.getSeconds())}`}function f(a,e){const t=e==="from"?"from_assistant_name":"to_assistant_name",s=e==="from"?"from_assistant_id":"to_assistant_id",o=a[t];if(o!=null&&String(o).trim()!==""&&String(o)!=="—")return String(o);const l=Number(a[s]);return Number.isFinite(l)&&l>0?`ID:${l}`:"—"}const g=async()=>{if(u.diagnosisId){m.value=!0;try{const a=await V({id:u.diagnosisId}),e=Array.isArray(a)?a:[];p.value=e}catch(a){console.error(a),p.value=[]}finally{m.value=!1}}};return C(()=>u.diagnosisId,()=>{g()},{immediate:!0}),y({refresh:g}),(a,e)=>{const t=L,s=k,o=P,l=A,S=$,I=M;return _(),b("div",K,[D((_(),h(S,{data:p.value,border:"",stripe:"","empty-text":"暂无指派记录"},{default:r(()=>[n(t,{label:"操作时间",width:"175",prop:"create_time_text"}),n(t,{label:"原医助","min-width":"120"},{default:r(({row:i})=>[c(d(f(i,"from")),1)]),_:1}),n(t,{label:"新医助","min-width":"120"},{default:r(({row:i})=>[c(d(f(i,"to")),1)]),_:1}),n(t,{label:"继承",width:"72",align:"center"},{default:r(({row:i})=>[Number(i.is_inherit)===1?(_(),h(s,{key:0,type:"success",size:"small"},{default:r(()=>[...e[0]||(e[0]=[c("是",-1)])]),_:1})):(_(),b("span",j,"否"))]),_:1}),n(t,{label:"快照·业务单创建人","min-width":"130","show-overflow-tooltip":""},{default:r(({row:i})=>[c(d(N(i)),1)]),_:1}),n(t,{label:"快照·业务单创建时间",width:"190"},{header:r(()=>[e[1]||(e[1]=E("span",null,"快照·业务单创建时间",-1)),n(l,{placement:"top",content:"related_po_create_time:触发本次操作的处方业务订单 create_time;与原文助一致时表示医助创建订单时间"},{default:r(()=>[n(o,{class:"assign-log-col-hint"},{default:r(()=>[n(B(F))]),_:1})]),_:1})]),default:r(({row:i})=>[c(d(x(i)),1)]),_:1}),n(t,{label:"操作人",width:"110",prop:"operator_name"}),n(t,{label:"操作账号",width:"120",prop:"operator_account","show-overflow-tooltip":""}),n(t,{label:"IP",width:"130",prop:"ip","show-overflow-tooltip":""})]),_:1},8,["data"])),[[I,m.value]])])}}}),Y=q(z,[["__scopeId","data-v-f670e3e6"]]);export{Y as default};
@@ -1 +1 @@
import{o as B,R as D,q as E,O,D as I,r as _,T as S,P as x,ac as W,s as h,ad as P,v as U,K as $,L as j,bt as H,p as K,M as v,dg as c}from"./.pnpm-Dwh6tNxD.js";import{af as Y}from"./tcm-RVDaIW5j.js";import{_ as q}from"./index-C9ilrjDr.js";const z={key:0,class:"watch-state"},F={key:1,class:"watch-state watch-error"},G=B({__name:"AssistantWatchCallDialog",props:{modelValue:{type:Boolean},diagnosisId:{}},emits:["update:modelValue","closed"],setup(R,{emit:A}){const u=R,g=A,y=K({get:()=>u.modelValue,set:t=>g("update:modelValue",t)}),r=v(null),l=v(!1),i=v(""),f=v("旁观视频通话"),n=new Map;let a=null,p=0;function w(t,e){return`${t}\0${String(e)}`}function N(t){return t.startsWith("patient_")?"患者":t.startsWith("doctor_")?"医护":t}async function T(t){if(!a||!r.value||t.streamType!==c.TYPE.STREAM_TYPE_MAIN)return;const e=w(t.userId,t.streamType);if(n.has(e))return;const o=document.createElement("div");o.className="watch-tile";const s=document.createElement("div");s.className="watch-tile-cap",s.textContent=N(t.userId);const d=document.createElement("div");d.className="watch-tile-view",o.appendChild(s),o.appendChild(d),r.value.appendChild(o),n.set(e,{wrap:o,userId:t.userId,streamType:t.streamType});try{await a.startRemoteVideo({userId:t.userId,streamType:t.streamType,view:d})}catch(b){console.warn("[AssistantWatchCall] startRemoteVideo",b)}}async function V(t){if(!a)return;const e=w(t.userId,t.streamType),o=n.get(e);if(o){try{await a.stopRemoteVideo({userId:t.userId,streamType:t.streamType})}catch{}o.wrap.remove(),n.delete(e)}}function C(){a&&(a.on(c.EVENT.REMOTE_VIDEO_AVAILABLE,T),a.on(c.EVENT.REMOTE_VIDEO_UNAVAILABLE,V))}function k(){a&&(a.off(c.EVENT.REMOTE_VIDEO_AVAILABLE,T),a.off(c.EVENT.REMOTE_VIDEO_UNAVAILABLE,V))}async function m(){if(k(),a){for(const[,t]of n){try{await a.stopRemoteVideo({userId:t.userId,streamType:t.streamType})}catch{}t.wrap.remove()}n.clear(),r.value&&(r.value.innerHTML="");try{await a.exitRoom()}catch{}try{a.destroy()}catch{}a=null}else n.clear(),r.value&&(r.value.innerHTML="")}async function L(){const t=++p;if(await m(),!u.diagnosisId){i.value="诊单无效";return}l.value=!0,i.value="",f.value="旁观视频通话";try{const e=await Y({diagnosis_id:u.diagnosisId});if(t!==p)return;e.patientName&&(f.value=`旁观视频通话 · ${e.patientName}`),a=c.create(),C();const o={sdkAppId:e.sdkAppId,userId:e.userId,userSig:e.userSig,autoReceiveAudio:!0,autoReceiveVideo:!0,...e.roomId!=null&&e.roomId>0?{roomId:e.roomId}:{strRoomId:e.strRoomId}};if(!(e.roomId!=null&&e.roomId>0)&&!e.strRoomId)throw new Error("缺少房间号");if(await a.enterRoom(o),t!==p){await m();return}l.value=!1}catch(e){l.value=!1;let o="进入房间失败";if(typeof e=="string")o=e;else if(e&&typeof e=="object"){const s=e;s.msg?o=String(s.msg):s.message&&(o=String(s.message))}i.value=o,await m()}}function M(){m(),l.value=!1,i.value="",f.value="旁观视频通话",g("closed")}return D(()=>[u.modelValue,u.diagnosisId],([t,e])=>{if(!t){p++,m();return}e>0&&L()}),(t,e)=>{const o=$,s=H;return E(),O(s,{modelValue:y.value,"onUpdate:modelValue":e[1]||(e[1]=d=>y.value=d),title:f.value,width:"760px","destroy-on-close":"","append-to-body":"","close-on-click-modal":!1,class:"assistant-watch-call-dialog",onClosed:M},{footer:I(()=>[e[3]||(e[3]=h("span",{class:"watch-hint"},"仅观看,不会开启摄像头与麦克风",-1)),U(o,{type:"primary",onClick:e[0]||(e[0]=d=>y.value=!1)},{default:I(()=>[...e[2]||(e[2]=[j("离开",-1)])]),_:1})]),default:I(()=>[l.value?(E(),_("div",z,"正在连接房间…")):i.value?(E(),_("div",F,S(i.value),1)):x("",!0),W(h("div",{ref_key:"gridRef",ref:r,class:"watch-grid"},null,512),[[P,!l.value&&!i.value]])]),_:1},8,["modelValue","title"])}}}),Z=q(G,[["__scopeId","data-v-7aff665d"]]);export{Z as default};
import{o as B,R as D,q as E,O,D as I,r as _,T as S,P as x,ac as W,s as h,ad as P,v as U,K as $,L as j,bt as H,p as K,M as v,dg as c}from"./.pnpm-Dwh6tNxD.js";import{af as Y}from"./tcm-WWBqr2Vo.js";import{_ as q}from"./index-C0Q8AuuZ.js";const z={key:0,class:"watch-state"},F={key:1,class:"watch-state watch-error"},G=B({__name:"AssistantWatchCallDialog",props:{modelValue:{type:Boolean},diagnosisId:{}},emits:["update:modelValue","closed"],setup(R,{emit:A}){const u=R,g=A,y=K({get:()=>u.modelValue,set:t=>g("update:modelValue",t)}),r=v(null),l=v(!1),i=v(""),f=v("旁观视频通话"),n=new Map;let a=null,p=0;function w(t,e){return`${t}\0${String(e)}`}function N(t){return t.startsWith("patient_")?"患者":t.startsWith("doctor_")?"医护":t}async function T(t){if(!a||!r.value||t.streamType!==c.TYPE.STREAM_TYPE_MAIN)return;const e=w(t.userId,t.streamType);if(n.has(e))return;const o=document.createElement("div");o.className="watch-tile";const s=document.createElement("div");s.className="watch-tile-cap",s.textContent=N(t.userId);const d=document.createElement("div");d.className="watch-tile-view",o.appendChild(s),o.appendChild(d),r.value.appendChild(o),n.set(e,{wrap:o,userId:t.userId,streamType:t.streamType});try{await a.startRemoteVideo({userId:t.userId,streamType:t.streamType,view:d})}catch(b){console.warn("[AssistantWatchCall] startRemoteVideo",b)}}async function V(t){if(!a)return;const e=w(t.userId,t.streamType),o=n.get(e);if(o){try{await a.stopRemoteVideo({userId:t.userId,streamType:t.streamType})}catch{}o.wrap.remove(),n.delete(e)}}function C(){a&&(a.on(c.EVENT.REMOTE_VIDEO_AVAILABLE,T),a.on(c.EVENT.REMOTE_VIDEO_UNAVAILABLE,V))}function k(){a&&(a.off(c.EVENT.REMOTE_VIDEO_AVAILABLE,T),a.off(c.EVENT.REMOTE_VIDEO_UNAVAILABLE,V))}async function m(){if(k(),a){for(const[,t]of n){try{await a.stopRemoteVideo({userId:t.userId,streamType:t.streamType})}catch{}t.wrap.remove()}n.clear(),r.value&&(r.value.innerHTML="");try{await a.exitRoom()}catch{}try{a.destroy()}catch{}a=null}else n.clear(),r.value&&(r.value.innerHTML="")}async function L(){const t=++p;if(await m(),!u.diagnosisId){i.value="诊单无效";return}l.value=!0,i.value="",f.value="旁观视频通话";try{const e=await Y({diagnosis_id:u.diagnosisId});if(t!==p)return;e.patientName&&(f.value=`旁观视频通话 · ${e.patientName}`),a=c.create(),C();const o={sdkAppId:e.sdkAppId,userId:e.userId,userSig:e.userSig,autoReceiveAudio:!0,autoReceiveVideo:!0,...e.roomId!=null&&e.roomId>0?{roomId:e.roomId}:{strRoomId:e.strRoomId}};if(!(e.roomId!=null&&e.roomId>0)&&!e.strRoomId)throw new Error("缺少房间号");if(await a.enterRoom(o),t!==p){await m();return}l.value=!1}catch(e){l.value=!1;let o="进入房间失败";if(typeof e=="string")o=e;else if(e&&typeof e=="object"){const s=e;s.msg?o=String(s.msg):s.message&&(o=String(s.message))}i.value=o,await m()}}function M(){m(),l.value=!1,i.value="",f.value="旁观视频通话",g("closed")}return D(()=>[u.modelValue,u.diagnosisId],([t,e])=>{if(!t){p++,m();return}e>0&&L()}),(t,e)=>{const o=$,s=H;return E(),O(s,{modelValue:y.value,"onUpdate:modelValue":e[1]||(e[1]=d=>y.value=d),title:f.value,width:"760px","destroy-on-close":"","append-to-body":"","close-on-click-modal":!1,class:"assistant-watch-call-dialog",onClosed:M},{footer:I(()=>[e[3]||(e[3]=h("span",{class:"watch-hint"},"仅观看,不会开启摄像头与麦克风",-1)),U(o,{type:"primary",onClick:e[0]||(e[0]=d=>y.value=!1)},{default:I(()=>[...e[2]||(e[2]=[j("离开",-1)])]),_:1})]),default:I(()=>[l.value?(E(),_("div",z,"正在连接房间…")):i.value?(E(),_("div",F,S(i.value),1)):x("",!0),W(h("div",{ref_key:"gridRef",ref:r,class:"watch-grid"},null,512),[[P,!l.value&&!i.value]])]),_:1},8,["modelValue","title"])}}}),Z=q(G,[["__scopeId","data-v-7aff665d"]]);export{Z as default};
@@ -1 +1 @@
import{o as N,di as O,R as P,q as d,r as f,v as o,D as i,K as V,L as n,P as h,ac as D,O as w,bj as L,bk as j,T as u,s as y,bi as z,M as v}from"./.pnpm-Dwh6tNxD.js";import M from"./RecordingPlaybackBlock-3c8TG8YE.js";import{U as k}from"./index-DBhmZUba.js";import{i as c,_ as q}from"./index-C9ilrjDr.js";import{aj as K,ak as x,al as A}from"./tcm-RVDaIW5j.js";import"./RecordingVideoPlayer-NZrEWtaq.js";import"./file-CNQVkxcM.js";const F={class:"call-record-panel"},G={key:0,class:"call-record-toolbar"},H={class:"call-record-empty"},J={class:"call-record-empty__desc"},Q={key:0,class:"text-primary"},W={key:1,class:"text-gray-400"},X=N({__name:"CallRecordPanel",props:{diagnosisId:{},readOnly:{type:Boolean,default:!1}},setup(_,{expose:R}){const r=_,p=v(!1),g=v([]),U=O("toolbarUploadRef"),m=async()=>{if(r.diagnosisId){p.value=!0;try{g.value=await K({diagnosis_id:r.diagnosisId})||[]}catch(e){console.error(e),g.value=[]}finally{p.value=!1}}};P(()=>r.diagnosisId,()=>{m()},{immediate:!0}),R({refresh:m});function C(e){return{1:"进行中",2:"已结束",3:"未接听",4:"已取消"}[e]??"—"}async function S(e){const t=b(e);if(!t){c.msgError("上传成功但未返回视频地址");return}try{const a=await A({diagnosis_id:r.diagnosisId});await x({diagnosis_id:r.diagnosisId,call_record_id:Number((a==null?void 0:a.id)||0),file_url:t}),c.msgSuccess("视频回放上传成功"),await m()}catch(a){c.msgError((a==null?void 0:a.message)||"写入回放失败")}}async function E(e,t){const a=b(t);if(!a){c.msgError("上传成功但未返回视频地址");return}try{await x({diagnosis_id:r.diagnosisId,call_record_id:Number(e.id||0),file_url:a}),c.msgSuccess("视频回放上传成功"),await m()}catch(l){c.msgError((l==null?void 0:l.message)||"写入回放失败")}}function b(e){var t,a;return String(((t=e==null?void 0:e.data)==null?void 0:t.uri)||((a=e==null?void 0:e.data)==null?void 0:a.url)||"").trim()}return(e,t)=>{const a=V,l=j,I=L,B=z;return d(),f("div",F,[_.readOnly?h("",!0):(d(),f("div",G,[o(k,{ref_key:"toolbarUploadRef",ref:U,type:"video",direct:"",multiple:!1,limit:1,"show-progress":!0,onSuccess:S},{default:i(()=>[o(a,{type:"primary"},{default:i(()=>[...t[0]||(t[0]=[n("上传视频",-1)])]),_:1})]),_:1},512)])),D((d(),w(I,{data:g.value,border:"",stripe:""},{empty:i(()=>[y("div",H,[t[1]||(t[1]=y("div",{class:"call-record-empty__title"},"暂无通话记录",-1)),y("div",J,u(_.readOnly?"暂无录制回放数据。":"现在可以直接点击上方“上传视频”。系统会自动生成一条默认通话记录来承载回放。"),1)])]),default:i(()=>[o(l,{label:"录制回放","min-width":"320"},{default:i(({row:s})=>[o(M,{"record-id":s.id,urls:s.recording_urls_list},null,8,["record-id","urls"])]),_:1}),o(l,{label:"开始时间",width:"170",prop:"start_time_text"}),o(l,{label:"结束时间",width:"170",prop:"end_time_text"}),o(l,{label:"通话类型",width:"100"},{default:i(({row:s})=>[n(u(s.call_type===1?"语音":"视频"),1)]),_:1}),o(l,{label:"房间号",width:"180"},{default:i(({row:s})=>[s.room_id?(d(),f("span",Q,u(s.room_id),1)):(d(),f("span",W,"—"))]),_:1}),o(l,{label:"时长",width:"110",prop:"duration_text"}),o(l,{label:"状态",width:"90"},{default:i(({row:s})=>[n(u(C(s.status)),1)]),_:1}),o(l,{label:"录制",width:"100"},{default:i(({row:s})=>[n(u(s.recording_status_text||"—"),1)]),_:1}),_.readOnly?h("",!0):(d(),w(l,{key:0,label:"上传回放",width:"180"},{default:i(({row:s})=>[o(k,{type:"video",direct:"",multiple:!1,limit:1,"show-progress":!0,onSuccess:T=>E(s,T)},{default:i(()=>[o(a,{type:"primary",plain:"",size:"small"},{default:i(()=>[...t[2]||(t[2]=[n("上传视频",-1)])]),_:1})]),_:1},8,["onSuccess"])]),_:1}))]),_:1},8,["data"])),[[B,p.value]])])}}}),sa=q(X,[["__scopeId","data-v-78d5c9e4"]]);export{sa as default};
import{o as N,di as O,R as P,q as d,r as f,v as o,D as i,K as V,L as n,P as h,ac as D,O as w,bj as L,bk as j,T as u,s as y,bi as z,M as v}from"./.pnpm-Dwh6tNxD.js";import M from"./RecordingPlaybackBlock-BeEg3fMj.js";import{U as k}from"./index-4SRyrKER.js";import{i as c,_ as q}from"./index-C0Q8AuuZ.js";import{aj as K,ak as x,al as A}from"./tcm-WWBqr2Vo.js";import"./RecordingVideoPlayer-xuuHPLFC.js";import"./file-BUuEowhq.js";const F={class:"call-record-panel"},G={key:0,class:"call-record-toolbar"},H={class:"call-record-empty"},J={class:"call-record-empty__desc"},Q={key:0,class:"text-primary"},W={key:1,class:"text-gray-400"},X=N({__name:"CallRecordPanel",props:{diagnosisId:{},readOnly:{type:Boolean,default:!1}},setup(_,{expose:R}){const r=_,p=v(!1),g=v([]),U=O("toolbarUploadRef"),m=async()=>{if(r.diagnosisId){p.value=!0;try{g.value=await K({diagnosis_id:r.diagnosisId})||[]}catch(e){console.error(e),g.value=[]}finally{p.value=!1}}};P(()=>r.diagnosisId,()=>{m()},{immediate:!0}),R({refresh:m});function C(e){return{1:"进行中",2:"已结束",3:"未接听",4:"已取消"}[e]??"—"}async function S(e){const t=b(e);if(!t){c.msgError("上传成功但未返回视频地址");return}try{const a=await A({diagnosis_id:r.diagnosisId});await x({diagnosis_id:r.diagnosisId,call_record_id:Number((a==null?void 0:a.id)||0),file_url:t}),c.msgSuccess("视频回放上传成功"),await m()}catch(a){c.msgError((a==null?void 0:a.message)||"写入回放失败")}}async function E(e,t){const a=b(t);if(!a){c.msgError("上传成功但未返回视频地址");return}try{await x({diagnosis_id:r.diagnosisId,call_record_id:Number(e.id||0),file_url:a}),c.msgSuccess("视频回放上传成功"),await m()}catch(l){c.msgError((l==null?void 0:l.message)||"写入回放失败")}}function b(e){var t,a;return String(((t=e==null?void 0:e.data)==null?void 0:t.uri)||((a=e==null?void 0:e.data)==null?void 0:a.url)||"").trim()}return(e,t)=>{const a=V,l=j,I=L,B=z;return d(),f("div",F,[_.readOnly?h("",!0):(d(),f("div",G,[o(k,{ref_key:"toolbarUploadRef",ref:U,type:"video",direct:"",multiple:!1,limit:1,"show-progress":!0,onSuccess:S},{default:i(()=>[o(a,{type:"primary"},{default:i(()=>[...t[0]||(t[0]=[n("上传视频",-1)])]),_:1})]),_:1},512)])),D((d(),w(I,{data:g.value,border:"",stripe:""},{empty:i(()=>[y("div",H,[t[1]||(t[1]=y("div",{class:"call-record-empty__title"},"暂无通话记录",-1)),y("div",J,u(_.readOnly?"暂无录制回放数据。":"现在可以直接点击上方“上传视频”。系统会自动生成一条默认通话记录来承载回放。"),1)])]),default:i(()=>[o(l,{label:"录制回放","min-width":"320"},{default:i(({row:s})=>[o(M,{"record-id":s.id,urls:s.recording_urls_list},null,8,["record-id","urls"])]),_:1}),o(l,{label:"开始时间",width:"170",prop:"start_time_text"}),o(l,{label:"结束时间",width:"170",prop:"end_time_text"}),o(l,{label:"通话类型",width:"100"},{default:i(({row:s})=>[n(u(s.call_type===1?"语音":"视频"),1)]),_:1}),o(l,{label:"房间号",width:"180"},{default:i(({row:s})=>[s.room_id?(d(),f("span",Q,u(s.room_id),1)):(d(),f("span",W,"—"))]),_:1}),o(l,{label:"时长",width:"110",prop:"duration_text"}),o(l,{label:"状态",width:"90"},{default:i(({row:s})=>[n(u(C(s.status)),1)]),_:1}),o(l,{label:"录制",width:"100"},{default:i(({row:s})=>[n(u(s.recording_status_text||"—"),1)]),_:1}),_.readOnly?h("",!0):(d(),w(l,{key:0,label:"上传回放",width:"180"},{default:i(({row:s})=>[o(k,{type:"video",direct:"",multiple:!1,limit:1,"show-progress":!0,onSuccess:T=>E(s,T)},{default:i(()=>[o(a,{type:"primary",plain:"",size:"small"},{default:i(()=>[...t[2]||(t[2]=[n("上传视频",-1)])]),_:1})]),_:1},8,["onSuccess"])]),_:1}))]),_:1},8,["data"])),[[B,p.value]])])}}}),sa=q(X,[["__scopeId","data-v-78d5c9e4"]]);export{sa as default};
@@ -1 +1 @@
import{o as T,ap as V,R as I,q as o,r as l,v as a,K as N,D as i,L as c,P as k,ac as z,bi as M,u as p,O as f,bk as O,T as _,F as P,br as j,s as F,bj as R,bB as A,M as w}from"./.pnpm-Dwh6tNxD.js";import{am as q}from"./tcm-RVDaIW5j.js";import{_ as H}from"./index-C9ilrjDr.js";const K={class:"case-record-list"},Y={key:0,class:"mb-3 flex justify-end"},G={key:0},J={key:1,class:"text-gray-400"},Q={class:"void-detail text-xs text-gray-500 mt-1"},U=T({__name:"CaseRecordList",props:{diagnosisId:{type:Number,default:0},readOnly:{type:Boolean,default:!1}},emits:["view","openPrescription"],setup(y,{expose:x,emit:C}){const m=y,b=C,r=w([]),d=w(!1),u=async()=>{if(m.diagnosisId){d.value=!0;try{const t=await q({diagnosis_id:m.diagnosisId});r.value=Array.isArray(t)?t:[]}catch(t){console.error("获取病历记录失败:",t),r.value=[]}finally{d.value=!1}}},S=t=>{if(!t)return"";const e=new Date(t*1e3);return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")} ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},B=t=>{b("view",t)},$=()=>{b("openPrescription")};return V(()=>{u()}),I(()=>m.diagnosisId,()=>{u()}),x({refresh:u}),(t,e)=>{const h=N,n=O,v=j,E=R,D=A,L=M;return o(),l("div",K,[y.readOnly?k("",!0):(o(),l("div",Y,[a(h,{type:"primary",size:"small",onClick:$},{default:i(()=>[...e[0]||(e[0]=[c("开方",-1)])]),_:1})])),z((o(),f(E,{data:p(r),border:""},{default:i(()=>[a(n,{prop:"prescription_date",label:"就诊日期",width:"120"}),a(n,{prop:"visit_no",label:"门诊号",width:"120"}),a(n,{prop:"clinical_diagnosis",label:"临床诊断","min-width":"160","show-overflow-tooltip":""}),a(n,{label:"处方摘要","min-width":"180"},{default:i(({row:s})=>[s.herbs&&s.herbs.length?(o(),l("span",G,_(s.herbs.slice(0,3).map(g=>`${g.name}${g.dosage}`).join("、"))+_(s.herbs.length>3?"...":""),1)):(o(),l("span",J,"—"))]),_:1}),a(n,{prop:"doctor_name",label:"医师",width:"90","show-overflow-tooltip":""}),a(n,{label:"状态",width:"140",align:"center"},{default:i(({row:s})=>[s.void_status===1?(o(),l(P,{key:0},[a(v,{type:"danger",size:"small"},{default:i(()=>[...e[1]||(e[1]=[c("已作废",-1)])]),_:1}),F("div",Q,_(s.void_by_name||"—")+" "+_(S(s.void_time)),1)],64)):(o(),f(v,{key:1,type:"success",size:"small"},{default:i(()=>[...e[2]||(e[2]=[c("正常",-1)])]),_:1}))]),_:1}),a(n,{label:"操作",width:"120",fixed:"right"},{default:i(({row:s})=>[a(h,{link:"",type:"primary",size:"small",onClick:g=>B(s)},{default:i(()=>[...e[3]||(e[3]=[c(" 查看 ",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[L,p(d)]]),!p(d)&&p(r).length===0?(o(),f(D,{key:1,description:"暂无病历记录,开方后会自动显示",class:"mt-4"})):k("",!0)])}}}),ee=H(U,[["__scopeId","data-v-043d2738"]]);export{ee as default};
import{o as T,ap as V,R as I,q as o,r as l,v as a,K as N,D as i,L as c,P as k,ac as z,bi as M,u as p,O as f,bk as O,T as _,F as P,br as j,s as F,bj as R,bB as A,M as w}from"./.pnpm-Dwh6tNxD.js";import{am as q}from"./tcm-WWBqr2Vo.js";import{_ as H}from"./index-C0Q8AuuZ.js";const K={class:"case-record-list"},Y={key:0,class:"mb-3 flex justify-end"},G={key:0},J={key:1,class:"text-gray-400"},Q={class:"void-detail text-xs text-gray-500 mt-1"},U=T({__name:"CaseRecordList",props:{diagnosisId:{type:Number,default:0},readOnly:{type:Boolean,default:!1}},emits:["view","openPrescription"],setup(y,{expose:x,emit:C}){const m=y,b=C,r=w([]),d=w(!1),u=async()=>{if(m.diagnosisId){d.value=!0;try{const t=await q({diagnosis_id:m.diagnosisId});r.value=Array.isArray(t)?t:[]}catch(t){console.error("获取病历记录失败:",t),r.value=[]}finally{d.value=!1}}},S=t=>{if(!t)return"";const e=new Date(t*1e3);return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")} ${String(e.getHours()).padStart(2,"0")}:${String(e.getMinutes()).padStart(2,"0")}`},B=t=>{b("view",t)},$=()=>{b("openPrescription")};return V(()=>{u()}),I(()=>m.diagnosisId,()=>{u()}),x({refresh:u}),(t,e)=>{const h=N,n=O,v=j,E=R,D=A,L=M;return o(),l("div",K,[y.readOnly?k("",!0):(o(),l("div",Y,[a(h,{type:"primary",size:"small",onClick:$},{default:i(()=>[...e[0]||(e[0]=[c("开方",-1)])]),_:1})])),z((o(),f(E,{data:p(r),border:""},{default:i(()=>[a(n,{prop:"prescription_date",label:"就诊日期",width:"120"}),a(n,{prop:"visit_no",label:"门诊号",width:"120"}),a(n,{prop:"clinical_diagnosis",label:"临床诊断","min-width":"160","show-overflow-tooltip":""}),a(n,{label:"处方摘要","min-width":"180"},{default:i(({row:s})=>[s.herbs&&s.herbs.length?(o(),l("span",G,_(s.herbs.slice(0,3).map(g=>`${g.name}${g.dosage}`).join("、"))+_(s.herbs.length>3?"...":""),1)):(o(),l("span",J,"—"))]),_:1}),a(n,{prop:"doctor_name",label:"医师",width:"90","show-overflow-tooltip":""}),a(n,{label:"状态",width:"140",align:"center"},{default:i(({row:s})=>[s.void_status===1?(o(),l(P,{key:0},[a(v,{type:"danger",size:"small"},{default:i(()=>[...e[1]||(e[1]=[c("已作废",-1)])]),_:1}),F("div",Q,_(s.void_by_name||"—")+" "+_(S(s.void_time)),1)],64)):(o(),f(v,{key:1,type:"success",size:"small"},{default:i(()=>[...e[2]||(e[2]=[c("正常",-1)])]),_:1}))]),_:1}),a(n,{label:"操作",width:"120",fixed:"right"},{default:i(({row:s})=>[a(h,{link:"",type:"primary",size:"small",onClick:g=>B(s)},{default:i(()=>[...e[3]||(e[3]=[c(" 查看 ",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["data"])),[[L,p(d)]]),!p(d)&&p(r).length===0?(o(),f(D,{key:1,description:"暂无病历记录,开方后会自动显示",class:"mt-4"})):k("",!0)])}}}),ee=H(U,[["__scopeId","data-v-043d2738"]]);export{ee as default};
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as o}from"./GancaoSubmissionReconcileButton.vue_vue_type_script_setup_true_lang-BhwrYz7M.js";import"./.pnpm-Dwh6tNxD.js";import"./tcm-WWBqr2Vo.js";import"./index-C0Q8AuuZ.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./GancaoSubmissionReconcileButton.vue_vue_type_script_setup_true_lang-C7bAXama.js";import"./.pnpm-Dwh6tNxD.js";import"./tcm-RVDaIW5j.js";import"./index-C9ilrjDr.js";export{o as default};
@@ -1 +1 @@
import{o as U,be as F,q as f,r as k,F as M,ac as D,O as E,D as t,L as u,K as G,v as r,bt as B,bh as q,b9 as P,aw as A,b6 as L,bc as T,bf as K,b7 as z,P as g,p as W,M as v,ba as $}from"./.pnpm-Dwh6tNxD.js";import{p as j}from"./tcm-RVDaIW5j.js";import{i as C}from"./index-C9ilrjDr.js";const X=U({__name:"GancaoSubmissionReconcileButton",props:{order:{}},emits:["resolved"],setup(N,{emit:w}){const d=N,y=w,V=W(()=>{var m,p,a;const i=String(((m=d.order)==null?void 0:m.pharmacy_claim_target)||"").trim().toLowerCase(),e=String(((p=d.order)==null?void 0:p.pharmacy_claim_status)||"").trim().toUpperCase(),n=Number(((a=d.order)==null?void 0:a.pharmacy_claim_lease_expires_at)||0),c=e==="PENDING"&&n>0&&n<=Math.floor(Date.now()/1e3);return i==="gancao"&&(c||["UNKNOWN","PENDING_RECONCILE"].includes(e))}),s=v(!1),_=v(!1),o=$({resolution:"CONFIRM_SUCCESS",remote_order_no:"",note:""});function O(){o.resolution="CONFIRM_SUCCESS",o.remote_order_no="",o.note="",s.value=!0}async function b(){var e;const i=Number((e=d.order)==null?void 0:e.id);if(i){if(o.resolution==="CONFIRM_SUCCESS"&&!o.remote_order_no.trim()){C.msgError("请填写甘草药方单号");return}if(!o.note.trim()){C.msgError("请填写甘草后台核对依据");return}_.value=!0;try{await j({id:i,resolution:o.resolution,remote_order_no:o.resolution==="CONFIRM_SUCCESS"?o.remote_order_no.trim():"",note:o.note.trim()}),C.msgSuccess("甘草提交核对已记录"),s.value=!1,y("resolved")}catch{}finally{_.value=!1}}}return(i,e)=>{const n=G,c=q,m=K,p=T,a=L,S=z,R=P,x=B,I=F("perms");return V.value?(f(),k(M,{key:0},[D((f(),E(n,{type:"danger",size:"small",plain:"",onClick:O},{default:t(()=>[...e[5]||(e[5]=[u("核对甘草提交",-1)])]),_:1})),[[I,["tcm.prescriptionOrder/confirmGancaoSubmission"]]]),r(x,{modelValue:s.value,"onUpdate:modelValue":e[4]||(e[4]=l=>s.value=l),title:"人工核对甘草提交",width:"min(92vw, 520px)","append-to-body":"","destroy-on-close":"","close-on-click-modal":!1},{footer:t(()=>[r(n,{onClick:e[3]||(e[3]=l=>s.value=!1)},{default:t(()=>[...e[8]||(e[8]=[u("取消",-1)])]),_:1}),r(n,{type:"primary",loading:_.value,onClick:b},{default:t(()=>[...e[9]||(e[9]=[u("确认并记录",-1)])]),_:1},8,["loading"])]),default:t(()=>[r(c,{title:"请先在甘草后台核对。本操作会写入不可变更的审计记录。",type:"warning",closable:!1,"show-icon":"",class:"mb-4"}),r(R,{"label-width":"100px",onSubmit:A(b,["prevent"])},{default:t(()=>[r(a,{label:"核对结果",required:""},{default:t(()=>[r(p,{modelValue:o.resolution,"onUpdate:modelValue":e[0]||(e[0]=l=>o.resolution=l)},{default:t(()=>[r(m,{label:"CONFIRM_SUCCESS"},{default:t(()=>[...e[6]||(e[6]=[u("确认已创建",-1)])]),_:1}),r(m,{label:"CONFIRM_NOT_CREATED"},{default:t(()=>[...e[7]||(e[7]=[u("确认未创建",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),o.resolution==="CONFIRM_SUCCESS"?(f(),E(a,{key:0,label:"甘草单号",required:""},{default:t(()=>[r(S,{modelValue:o.remote_order_no,"onUpdate:modelValue":e[1]||(e[1]=l=>o.remote_order_no=l),maxlength:"64",clearable:""},null,8,["modelValue"])]),_:1})):g("",!0),r(a,{label:"核对依据",required:""},{default:t(()=>[r(S,{modelValue:o.note,"onUpdate:modelValue":e[2]||(e[2]=l=>o.note=l),type:"textarea",rows:3,maxlength:"1000","show-word-limit":"",placeholder:"例如:核对时间、甘草后台查询条件及结果"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue"])],64)):g("",!0)}}});export{X as _};
import{o as U,be as F,q as f,r as k,F as M,ac as D,O as E,D as t,L as u,K as G,v as r,bt as B,bh as q,b9 as P,aw as A,b6 as L,bc as T,bf as K,b7 as z,P as g,p as W,M as v,ba as $}from"./.pnpm-Dwh6tNxD.js";import{p as j}from"./tcm-WWBqr2Vo.js";import{i as C}from"./index-C0Q8AuuZ.js";const X=U({__name:"GancaoSubmissionReconcileButton",props:{order:{}},emits:["resolved"],setup(N,{emit:w}){const d=N,y=w,V=W(()=>{var m,p,a;const i=String(((m=d.order)==null?void 0:m.pharmacy_claim_target)||"").trim().toLowerCase(),e=String(((p=d.order)==null?void 0:p.pharmacy_claim_status)||"").trim().toUpperCase(),n=Number(((a=d.order)==null?void 0:a.pharmacy_claim_lease_expires_at)||0),c=e==="PENDING"&&n>0&&n<=Math.floor(Date.now()/1e3);return i==="gancao"&&(c||["UNKNOWN","PENDING_RECONCILE"].includes(e))}),s=v(!1),_=v(!1),o=$({resolution:"CONFIRM_SUCCESS",remote_order_no:"",note:""});function O(){o.resolution="CONFIRM_SUCCESS",o.remote_order_no="",o.note="",s.value=!0}async function b(){var e;const i=Number((e=d.order)==null?void 0:e.id);if(i){if(o.resolution==="CONFIRM_SUCCESS"&&!o.remote_order_no.trim()){C.msgError("请填写甘草药方单号");return}if(!o.note.trim()){C.msgError("请填写甘草后台核对依据");return}_.value=!0;try{await j({id:i,resolution:o.resolution,remote_order_no:o.resolution==="CONFIRM_SUCCESS"?o.remote_order_no.trim():"",note:o.note.trim()}),C.msgSuccess("甘草提交核对已记录"),s.value=!1,y("resolved")}catch{}finally{_.value=!1}}}return(i,e)=>{const n=G,c=q,m=K,p=T,a=L,S=z,R=P,x=B,I=F("perms");return V.value?(f(),k(M,{key:0},[D((f(),E(n,{type:"danger",size:"small",plain:"",onClick:O},{default:t(()=>[...e[5]||(e[5]=[u("核对甘草提交",-1)])]),_:1})),[[I,["tcm.prescriptionOrder/confirmGancaoSubmission"]]]),r(x,{modelValue:s.value,"onUpdate:modelValue":e[4]||(e[4]=l=>s.value=l),title:"人工核对甘草提交",width:"min(92vw, 520px)","append-to-body":"","destroy-on-close":"","close-on-click-modal":!1},{footer:t(()=>[r(n,{onClick:e[3]||(e[3]=l=>s.value=!1)},{default:t(()=>[...e[8]||(e[8]=[u("取消",-1)])]),_:1}),r(n,{type:"primary",loading:_.value,onClick:b},{default:t(()=>[...e[9]||(e[9]=[u("确认并记录",-1)])]),_:1},8,["loading"])]),default:t(()=>[r(c,{title:"请先在甘草后台核对。本操作会写入不可变更的审计记录。",type:"warning",closable:!1,"show-icon":"",class:"mb-4"}),r(R,{"label-width":"100px",onSubmit:A(b,["prevent"])},{default:t(()=>[r(a,{label:"核对结果",required:""},{default:t(()=>[r(p,{modelValue:o.resolution,"onUpdate:modelValue":e[0]||(e[0]=l=>o.resolution=l)},{default:t(()=>[r(m,{label:"CONFIRM_SUCCESS"},{default:t(()=>[...e[6]||(e[6]=[u("确认已创建",-1)])]),_:1}),r(m,{label:"CONFIRM_NOT_CREATED"},{default:t(()=>[...e[7]||(e[7]=[u("确认未创建",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),o.resolution==="CONFIRM_SUCCESS"?(f(),E(a,{key:0,label:"甘草单号",required:""},{default:t(()=>[r(S,{modelValue:o.remote_order_no,"onUpdate:modelValue":e[1]||(e[1]=l=>o.remote_order_no=l),maxlength:"64",clearable:""},null,8,["modelValue"])]),_:1})):g("",!0),r(a,{label:"核对依据",required:""},{default:t(()=>[r(S,{modelValue:o.note,"onUpdate:modelValue":e[2]||(e[2]=l=>o.note=l),type:"textarea",rows:3,maxlength:"1000","show-word-limit":"",placeholder:"例如:核对时间、甘草后台查询条件及结果"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1},8,["modelValue"])],64)):g("",!0)}}});export{X as _};
@@ -1 +1 @@
import{o as F,R as q,q as t,r as n,v as i,D as c,s as o,L as _,bh as G,w as H,u as x,cV as $,K as j,by as J,ac as K,F as E,G as O,O as f,bB as W,P as v,bi as Q,M as m,p as U,ae as X,T as r,br as Z,aa as ee,bq as se,a8 as ae,E as C}from"./.pnpm-Dwh6tNxD.js";import{d as te}from"./dayjs-Cbxn44tS.js";import{ar as ne,as as oe}from"./tcm-RVDaIW5j.js";import{p as re}from"./im-business-message-parse-CVnz1EnV.js";import{_ as le}from"./index-C9ilrjDr.js";const ie={class:"im-chat-record-panel"},ce={class:"toolbar mb-3"},de={class:"chat-wrap"},_e={key:0,class:"chat-list"},ue={class:"meta"},fe={class:"name"},me={class:"time"},pe={class:"bubble"},ye={key:0,class:"friendly-text"},ge={class:"friendly-main"},ve={key:0,class:"friendly-sub"},he={key:1,class:"text-content"},we={key:2,class:"text-content"},be={key:3,class:"muted"},ke=F({__name:"ImChatRecordPanel",props:{diagnosisId:{}},setup(B,{expose:M}){const u=B,d=m(!1),p=m(!1),y=ae([]),L=m(""),g=m(""),D={text:"",image:"图片",file:"文件",sound:"语音",video:"视频",location:"位置",custom:"自定义",face:"表情",other:""},h=U(()=>y.value.map(e=>{const a=P(e);let l="";return a!=null&&a.tag?l=a.tag:l=D[e.msg_type]||(e.msg_type!=="other"?e.msg_type:""),{raw:e,friendly:a,tag:l}}));function N(e){if(e==null||!e)return"—";const a=e>1e12?Math.floor(e/1e3):e;return te.unix(a).format("YYYY-MM-DD HH:mm:ss")}function P(e){const a=(e.text||"").trim();if(!a)return null;const l=a.startsWith("{")&&(/\bbusinessID\b/.test(a)||/\bcmd\b/.test(a));return e.msg_type==="custom"||l?re(a):null}function R(e){return e.is_from_doctor?e.from_staff_name?`医生(${e.from_staff_name}`:"医生/员工":g.value?`患者(${g.value}`:"患者"}async function w(){if(u.diagnosisId){d.value=!0;try{const e=await ne({diagnosis_id:u.diagnosisId,only_archived:1});y.value=(e==null?void 0:e.lists)||[],L.value=(e==null?void 0:e.patient_im_id)||"",g.value=(e==null?void 0:e.patient_name)||""}catch(e){console.error(e),y.value=[]}finally{d.value=!1}}}function b(){w()}async function S(){if(u.diagnosisId){p.value=!0;try{await oe({diagnosis_id:u.diagnosisId}),C.success('已发起后台同步,几秒后请点击"重新加载已归档"查看新消息')}catch(e){console.error(e),C.error("发起同步失败")}finally{p.value=!1}}}return q(()=>u.diagnosisId,()=>{w()},{immediate:!0}),M({refresh:b}),(e,a)=>{const l=G,k=H,I=j,T=Z,V=ee,Y=se,z=W,A=Q;return t(),n("div",ie,[i(l,{type:"info","show-icon":"",closable:!1,class:"mb-4",title:"说明"},{default:c(()=>[...a[0]||(a[0]=[o("p",{class:"panel-tip"},[_(" 展示单聊记录:已合并患者 与 "),o("strong",null,"所有医生 / 医助账号"),_("分别产生的会话,按时间排序。 数据由后台定时任务从腾讯云 IM 漫游消息同步至本地归档;点击下方按钮可立即触发后台同步。 ")],-1)])]),_:1}),o("div",ce,[i(I,{type:"primary",link:"",loading:p.value,onClick:S},{default:c(()=>[i(k,{class:"mr-1"},{default:c(()=>[i(x($))]),_:1}),a[1]||(a[1]=_(" 同步最新(后台异步) ",-1))]),_:1},8,["loading"]),i(I,{type:"primary",link:"",loading:d.value,onClick:b},{default:c(()=>[i(k,{class:"mr-1"},{default:c(()=>[i(x(J))]),_:1}),a[2]||(a[2]=_(" 重新加载已归档 ",-1))]),_:1},8,["loading"])]),K((t(),n("div",de,[!d.value&&h.value.length?(t(),n("div",_e,[(t(!0),n(E,null,O(h.value,s=>(t(),n("div",{key:s.raw.msg_id,class:X(["chat-row",s.raw.is_from_doctor?"from-doctor":"from-patient"])},[o("div",ue,[o("span",fe,r(R(s.raw)),1),o("span",me,r(N(s.raw.time)),1),s.tag?(t(),f(T,{key:0,size:"small",type:"info",class:"ml-2"},{default:c(()=>[_(r(s.tag),1)]),_:2},1024)):v("",!0)]),o("div",pe,[s.raw.msg_type==="image"&&s.raw.image_url?(t(),f(V,{key:0,src:s.raw.image_url,"preview-src-list":[s.raw.image_url],fit:"contain",class:"chat-img"},null,8,["src","preview-src-list"])):(s.raw.msg_type==="file"||s.raw.msg_type==="sound"||s.raw.msg_type==="video")&&s.raw.file_url?(t(),f(Y,{key:1,href:s.raw.file_url,target:"_blank",type:"primary"},{default:c(()=>[_(r(s.raw.file_name||"打开文件"),1)]),_:2},1032,["href"])):(t(),n(E,{key:2},[s.friendly?(t(),n("div",ye,[o("div",ge,r(s.friendly.main),1),s.friendly.sub?(t(),n("div",ve,r(s.friendly.sub),1)):v("",!0)])):s.raw.msg_type==="text"&&s.raw.text?(t(),n("div",he,r(s.raw.text),1)):s.raw.text?(t(),n("div",we,r(s.raw.text),1)):(t(),n("span",be,"(无法展示该消息类型)"))],64))])],2))),128))])):d.value?v("",!0):(t(),f(z,{key:1,description:"暂无 IM 聊天记录"}))])),[[A,d.value]])])}}}),Me=le(ke,[["__scopeId","data-v-58b699dd"]]);export{Me as default};
import{o as F,R as q,q as t,r as n,v as i,D as c,s as o,L as _,bh as G,w as H,u as x,cV as $,K as j,by as J,ac as K,F as E,G as O,O as f,bB as W,P as v,bi as Q,M as m,p as U,ae as X,T as r,br as Z,aa as ee,bq as se,a8 as ae,E as C}from"./.pnpm-Dwh6tNxD.js";import{d as te}from"./dayjs-Cbxn44tS.js";import{ar as ne,as as oe}from"./tcm-WWBqr2Vo.js";import{p as re}from"./im-business-message-parse-CVnz1EnV.js";import{_ as le}from"./index-C0Q8AuuZ.js";const ie={class:"im-chat-record-panel"},ce={class:"toolbar mb-3"},de={class:"chat-wrap"},_e={key:0,class:"chat-list"},ue={class:"meta"},fe={class:"name"},me={class:"time"},pe={class:"bubble"},ye={key:0,class:"friendly-text"},ge={class:"friendly-main"},ve={key:0,class:"friendly-sub"},he={key:1,class:"text-content"},we={key:2,class:"text-content"},be={key:3,class:"muted"},ke=F({__name:"ImChatRecordPanel",props:{diagnosisId:{}},setup(B,{expose:M}){const u=B,d=m(!1),p=m(!1),y=ae([]),L=m(""),g=m(""),D={text:"",image:"图片",file:"文件",sound:"语音",video:"视频",location:"位置",custom:"自定义",face:"表情",other:""},h=U(()=>y.value.map(e=>{const a=P(e);let l="";return a!=null&&a.tag?l=a.tag:l=D[e.msg_type]||(e.msg_type!=="other"?e.msg_type:""),{raw:e,friendly:a,tag:l}}));function N(e){if(e==null||!e)return"—";const a=e>1e12?Math.floor(e/1e3):e;return te.unix(a).format("YYYY-MM-DD HH:mm:ss")}function P(e){const a=(e.text||"").trim();if(!a)return null;const l=a.startsWith("{")&&(/\bbusinessID\b/.test(a)||/\bcmd\b/.test(a));return e.msg_type==="custom"||l?re(a):null}function R(e){return e.is_from_doctor?e.from_staff_name?`医生(${e.from_staff_name}`:"医生/员工":g.value?`患者(${g.value}`:"患者"}async function w(){if(u.diagnosisId){d.value=!0;try{const e=await ne({diagnosis_id:u.diagnosisId,only_archived:1});y.value=(e==null?void 0:e.lists)||[],L.value=(e==null?void 0:e.patient_im_id)||"",g.value=(e==null?void 0:e.patient_name)||""}catch(e){console.error(e),y.value=[]}finally{d.value=!1}}}function b(){w()}async function S(){if(u.diagnosisId){p.value=!0;try{await oe({diagnosis_id:u.diagnosisId}),C.success('已发起后台同步,几秒后请点击"重新加载已归档"查看新消息')}catch(e){console.error(e),C.error("发起同步失败")}finally{p.value=!1}}}return q(()=>u.diagnosisId,()=>{w()},{immediate:!0}),M({refresh:b}),(e,a)=>{const l=G,k=H,I=j,T=Z,V=ee,Y=se,z=W,A=Q;return t(),n("div",ie,[i(l,{type:"info","show-icon":"",closable:!1,class:"mb-4",title:"说明"},{default:c(()=>[...a[0]||(a[0]=[o("p",{class:"panel-tip"},[_(" 展示单聊记录:已合并患者 与 "),o("strong",null,"所有医生 / 医助账号"),_("分别产生的会话,按时间排序。 数据由后台定时任务从腾讯云 IM 漫游消息同步至本地归档;点击下方按钮可立即触发后台同步。 ")],-1)])]),_:1}),o("div",ce,[i(I,{type:"primary",link:"",loading:p.value,onClick:S},{default:c(()=>[i(k,{class:"mr-1"},{default:c(()=>[i(x($))]),_:1}),a[1]||(a[1]=_(" 同步最新(后台异步) ",-1))]),_:1},8,["loading"]),i(I,{type:"primary",link:"",loading:d.value,onClick:b},{default:c(()=>[i(k,{class:"mr-1"},{default:c(()=>[i(x(J))]),_:1}),a[2]||(a[2]=_(" 重新加载已归档 ",-1))]),_:1},8,["loading"])]),K((t(),n("div",de,[!d.value&&h.value.length?(t(),n("div",_e,[(t(!0),n(E,null,O(h.value,s=>(t(),n("div",{key:s.raw.msg_id,class:X(["chat-row",s.raw.is_from_doctor?"from-doctor":"from-patient"])},[o("div",ue,[o("span",fe,r(R(s.raw)),1),o("span",me,r(N(s.raw.time)),1),s.tag?(t(),f(T,{key:0,size:"small",type:"info",class:"ml-2"},{default:c(()=>[_(r(s.tag),1)]),_:2},1024)):v("",!0)]),o("div",pe,[s.raw.msg_type==="image"&&s.raw.image_url?(t(),f(V,{key:0,src:s.raw.image_url,"preview-src-list":[s.raw.image_url],fit:"contain",class:"chat-img"},null,8,["src","preview-src-list"])):(s.raw.msg_type==="file"||s.raw.msg_type==="sound"||s.raw.msg_type==="video")&&s.raw.file_url?(t(),f(Y,{key:1,href:s.raw.file_url,target:"_blank",type:"primary"},{default:c(()=>[_(r(s.raw.file_name||"打开文件"),1)]),_:2},1032,["href"])):(t(),n(E,{key:2},[s.friendly?(t(),n("div",ye,[o("div",ge,r(s.friendly.main),1),s.friendly.sub?(t(),n("div",ve,r(s.friendly.sub),1)):v("",!0)])):s.raw.msg_type==="text"&&s.raw.text?(t(),n("div",he,r(s.raw.text),1)):s.raw.text?(t(),n("div",we,r(s.raw.text),1)):(t(),n("span",be,"(无法展示该消息类型)"))],64))])],2))),128))])):d.value?v("",!0):(t(),f(z,{key:1,description:"暂无 IM 聊天记录"}))])),[[A,d.value]])])}}}),Me=le(ke,[["__scopeId","data-v-58b699dd"]]);export{Me as default};
@@ -1 +1 @@
import{o as S,q as a,r as l,ae as x,v as r,D as m,L as d,T as i,a0 as D,s as n,O as g,br as G,P as B,aa as K,u as v,bE as L,w as q,bF as A,bG as H,bH as O,F as P,K as U,p as u}from"./.pnpm-Dwh6tNxD.js";import{t as j,_ as J}from"./index-C9ilrjDr.js";const Q={class:"msg-body"},R={class:"msg-meta"},W={class:"msg-sender"},X={class:"msg-time"},Y={key:0,class:"content-text"},Z={key:2,class:"content-pending"},ee=["src"],se={key:4,class:"content-pending"},te=["src"],ae={key:6,class:"content-pending"},ne={key:7,class:"content-file"},le={class:"file-meta"},ie=["title"],oe={class:"file-info"},ce={key:8,class:"content-fallback"},re={class:"fallback-title"},me={class:"fallback-desc"},ue=S({__name:"MessageBubble",props:{message:{}},setup(s){const o=s,w=u(()=>o.message.from_is_staff),c=u(()=>(o.message.media||[]).find(t=>t.status===1)??null),_=u(()=>{const e=o.message.from_profile;return e&&e.name||o.message.from_user}),z=u(()=>{const e=o.message.from_profile;return(e==null?void 0:e.avatar)||""}),F=u(()=>(_.value||"").slice(-2)||"?"),E=u(()=>{const e=o.message.msgtype;return e==="image"||e==="video"||e==="voice"?"bubble-media":e==="file"?"bubble-file":"bubble-text"}),C=u(()=>{switch(o.message.msgtype){case"link":return"[链接]";case"weapp":return"[小程序]";case"chatrecord":return"[聊天记录]";case"location":return"[位置]";case"card":return"[名片]";case"meeting":return"[会议]";case"docmsg":return"[文档]";case"mixed":return"[混合消息]";case"emotion":return"[表情]";default:return`[${o.message.msgtype}]`}});function M(e){return e?j(e*1e3,"mm-dd hh:MM"):""}function N(e){return e?e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/1024/1024).toFixed(2)} MB`:`${(e/1024/1024/1024).toFixed(2)} GB`:""}function $(e){window.open(e,"_blank","noopener")}return(e,t)=>{var k,y,p,h;const T=D,b=G,V=K,f=q,I=U;return a(),l("div",{class:x(["msg-bubble",{"is-staff":w.value}])},[r(T,{class:"msg-avatar",size:36,src:z.value},{default:m(()=>[d(i(F.value),1)]),_:1},8,["src"]),n("div",Q,[n("div",R,[n("span",W,i(_.value),1),n("span",X,i(M(s.message.send_time)),1),s.message.action==="recall"?(a(),g(b,{key:0,size:"small",type:"info"},{default:m(()=>[...t[1]||(t[1]=[d(" 已撤回 ",-1)])]),_:1})):B("",!0)]),n("div",{class:x(["msg-content",E.value])},[s.message.msgtype==="text"||s.message.msgtype==="markdown"?(a(),l("div",Y,i(s.message.content),1)):s.message.msgtype==="image"&&((k=c.value)!=null&&k.file_url)?(a(),g(V,{key:1,src:c.value.file_url,"preview-src-list":[c.value.file_url],fit:"contain",class:"content-image","hide-on-click-modal":""},null,8,["src","preview-src-list"])):s.message.msgtype==="image"?(a(),l("div",Z,[r(f,null,{default:m(()=>[r(v(L))]),_:1}),t[2]||(t[2]=n("span",null,"图片下载中…",-1))])):s.message.msgtype==="video"&&((y=c.value)!=null&&y.file_url)?(a(),l("video",{key:3,src:c.value.file_url,controls:"",class:"content-video"},null,8,ee)):s.message.msgtype==="video"?(a(),l("div",se,[r(f,null,{default:m(()=>[r(v(A))]),_:1}),t[3]||(t[3]=n("span",null,"视频下载中…",-1))])):s.message.msgtype==="voice"&&((p=c.value)!=null&&p.file_url)?(a(),l("audio",{key:5,src:c.value.file_url,controls:"",class:"content-audio"},null,8,te)):s.message.msgtype==="voice"?(a(),l("div",ae,[r(f,null,{default:m(()=>[r(v(H))]),_:1}),n("span",null,"语音下载中…("+i(s.message.play_length)+"s",1)])):s.message.msgtype==="file"?(a(),l("div",ne,[r(f,{size:24},{default:m(()=>[r(v(O))]),_:1}),n("div",le,[n("div",{class:"file-name",title:s.message.file_name},i(s.message.file_name||"未命名文件"),9,ie),n("div",oe,[d(i(N(s.message.file_size))+" ",1),s.message.file_ext?(a(),l(P,{key:0},[d("· "+i(s.message.file_ext),1)],64)):B("",!0)])]),(h=c.value)!=null&&h.file_url?(a(),g(I,{key:0,size:"small",type:"primary",link:"",onClick:t[0]||(t[0]=de=>$(c.value.file_url))},{default:m(()=>[...t[4]||(t[4]=[d(" 下载 ",-1)])]),_:1})):(a(),g(b,{key:1,size:"small",type:"info"},{default:m(()=>[...t[5]||(t[5]=[d("下载中…",-1)])]),_:1}))])):(a(),l("div",ce,[n("div",re,i(C.value),1),n("div",me,i(s.message.content),1)]))],2)])],2)}}}),ve=J(ue,[["__scopeId","data-v-b5ff1168"]]);export{ve as default};
import{o as S,q as a,r as l,ae as x,v as r,D as m,L as d,T as i,a0 as D,s as n,O as g,br as G,P as B,aa as K,u as v,bE as L,w as q,bF as A,bG as H,bH as O,F as P,K as U,p as u}from"./.pnpm-Dwh6tNxD.js";import{t as j,_ as J}from"./index-C0Q8AuuZ.js";const Q={class:"msg-body"},R={class:"msg-meta"},W={class:"msg-sender"},X={class:"msg-time"},Y={key:0,class:"content-text"},Z={key:2,class:"content-pending"},ee=["src"],se={key:4,class:"content-pending"},te=["src"],ae={key:6,class:"content-pending"},ne={key:7,class:"content-file"},le={class:"file-meta"},ie=["title"],oe={class:"file-info"},ce={key:8,class:"content-fallback"},re={class:"fallback-title"},me={class:"fallback-desc"},ue=S({__name:"MessageBubble",props:{message:{}},setup(s){const o=s,w=u(()=>o.message.from_is_staff),c=u(()=>(o.message.media||[]).find(t=>t.status===1)??null),_=u(()=>{const e=o.message.from_profile;return e&&e.name||o.message.from_user}),z=u(()=>{const e=o.message.from_profile;return(e==null?void 0:e.avatar)||""}),F=u(()=>(_.value||"").slice(-2)||"?"),E=u(()=>{const e=o.message.msgtype;return e==="image"||e==="video"||e==="voice"?"bubble-media":e==="file"?"bubble-file":"bubble-text"}),C=u(()=>{switch(o.message.msgtype){case"link":return"[链接]";case"weapp":return"[小程序]";case"chatrecord":return"[聊天记录]";case"location":return"[位置]";case"card":return"[名片]";case"meeting":return"[会议]";case"docmsg":return"[文档]";case"mixed":return"[混合消息]";case"emotion":return"[表情]";default:return`[${o.message.msgtype}]`}});function M(e){return e?j(e*1e3,"mm-dd hh:MM"):""}function N(e){return e?e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/1024/1024).toFixed(2)} MB`:`${(e/1024/1024/1024).toFixed(2)} GB`:""}function $(e){window.open(e,"_blank","noopener")}return(e,t)=>{var k,y,p,h;const T=D,b=G,V=K,f=q,I=U;return a(),l("div",{class:x(["msg-bubble",{"is-staff":w.value}])},[r(T,{class:"msg-avatar",size:36,src:z.value},{default:m(()=>[d(i(F.value),1)]),_:1},8,["src"]),n("div",Q,[n("div",R,[n("span",W,i(_.value),1),n("span",X,i(M(s.message.send_time)),1),s.message.action==="recall"?(a(),g(b,{key:0,size:"small",type:"info"},{default:m(()=>[...t[1]||(t[1]=[d(" 已撤回 ",-1)])]),_:1})):B("",!0)]),n("div",{class:x(["msg-content",E.value])},[s.message.msgtype==="text"||s.message.msgtype==="markdown"?(a(),l("div",Y,i(s.message.content),1)):s.message.msgtype==="image"&&((k=c.value)!=null&&k.file_url)?(a(),g(V,{key:1,src:c.value.file_url,"preview-src-list":[c.value.file_url],fit:"contain",class:"content-image","hide-on-click-modal":""},null,8,["src","preview-src-list"])):s.message.msgtype==="image"?(a(),l("div",Z,[r(f,null,{default:m(()=>[r(v(L))]),_:1}),t[2]||(t[2]=n("span",null,"图片下载中…",-1))])):s.message.msgtype==="video"&&((y=c.value)!=null&&y.file_url)?(a(),l("video",{key:3,src:c.value.file_url,controls:"",class:"content-video"},null,8,ee)):s.message.msgtype==="video"?(a(),l("div",se,[r(f,null,{default:m(()=>[r(v(A))]),_:1}),t[3]||(t[3]=n("span",null,"视频下载中…",-1))])):s.message.msgtype==="voice"&&((p=c.value)!=null&&p.file_url)?(a(),l("audio",{key:5,src:c.value.file_url,controls:"",class:"content-audio"},null,8,te)):s.message.msgtype==="voice"?(a(),l("div",ae,[r(f,null,{default:m(()=>[r(v(H))]),_:1}),n("span",null,"语音下载中…("+i(s.message.play_length)+"s",1)])):s.message.msgtype==="file"?(a(),l("div",ne,[r(f,{size:24},{default:m(()=>[r(v(O))]),_:1}),n("div",le,[n("div",{class:"file-name",title:s.message.file_name},i(s.message.file_name||"未命名文件"),9,ie),n("div",oe,[d(i(N(s.message.file_size))+" ",1),s.message.file_ext?(a(),l(P,{key:0},[d("· "+i(s.message.file_ext),1)],64)):B("",!0)])]),(h=c.value)!=null&&h.file_url?(a(),g(I,{key:0,size:"small",type:"primary",link:"",onClick:t[0]||(t[0]=de=>$(c.value.file_url))},{default:m(()=>[...t[4]||(t[4]=[d(" 下载 ",-1)])]),_:1})):(a(),g(b,{key:1,size:"small",type:"info"},{default:m(()=>[...t[5]||(t[5]=[d("下载中…",-1)])]),_:1}))])):(a(),l("div",ce,[n("div",re,i(C.value),1),n("div",me,i(s.message.content),1)]))],2)])],2)}}}),ve=J(ue,[["__scopeId","data-v-b5ff1168"]]);export{ve as default};
@@ -1,2 +1,2 @@
import{o as ie,R as oe,q as n,r as o,O as k,K as le,D as r,L as P,P as m,v as l,s as d,F as w,G as E,bB as ae,b7 as re,bt as de,p as ue,M as g,T as U,aa as me,u as V,d7 as z,aw as M,w as ce,bH as pe,e as ge}from"./.pnpm-Dwh6tNxD.js";import{_ as fe}from"./picker-DYD_beSt.js";import{e as ve,c as _e,i as f,_ as ye}from"./index-C9ilrjDr.js";import{a as T,d as he}from"./patient-SYRPmtkf.js";import{h as ke}from"./perm-3ZlDfnJ_.js";import"./index-BM6NmNnG.js";import"./index-DB4KfTa0.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./index-4fo3NoYp.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./usePaging-DOuAwzL9.js";const we={class:"note-timeline-wrap"},Ie={key:0,class:"timeline-actions"},Ce={class:"upload-trigger"},be={class:"upload-trigger"},xe={key:1,class:"note-timeline"},Ee={class:"timeline-date"},Ve={class:"timeline-body"},Ne={key:0,class:"timeline-content"},Se={key:1,class:"timeline-images"},De={key:2,class:"timeline-images"},Be={key:0,class:"thumb-wrap"},Ae={key:1,class:"file-wrap"},Pe=["href","title"],Ue={class:"file-name"},W=8e3,ze=ie({__name:"NoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(u,{emit:j}){const c=u,I=j,X=ue(()=>ke(["doctor.appointment/addDoctorNote"])),v=g(!1),C=g(""),N=g(!1),q=ve(),_=t=>q.getImageUrl(t),S=g([]),D=g([]),y=g(0),h=g(0),H=["jpg","jpeg","png","gif","bmp","webp","svg"],B=t=>{var i;const e=((i=t.split(".").pop())==null?void 0:i.toLowerCase().split("?")[0])||"";return H.includes(e)},$=t=>{var i;const e=t.split("/");return decodeURIComponent(((i=e[e.length-1])==null?void 0:i.split("?")[0])||"文件")},K=t=>t.filter(B).map(_),Z=(t,e)=>{const i=t.filter(B),b=t[e];return i.indexOf(b)},J=t=>t?t.split(`
import{o as ie,R as oe,q as n,r as o,O as k,K as le,D as r,L as P,P as m,v as l,s as d,F as w,G as E,bB as ae,b7 as re,bt as de,p as ue,M as g,T as U,aa as me,u as V,d7 as z,aw as M,w as ce,bH as pe,e as ge}from"./.pnpm-Dwh6tNxD.js";import{_ as fe}from"./picker-2bpe8Dva.js";import{e as ve,c as _e,i as f,_ as ye}from"./index-C0Q8AuuZ.js";import{a as T,d as he}from"./patient-SxYcZ8aN.js";import{h as ke}from"./perm-B_zXG10L.js";import"./index-CfJcNX3X.js";import"./index-B-j4AceK.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./index-39SS-XKl.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./usePaging-DOuAwzL9.js";const we={class:"note-timeline-wrap"},Ie={key:0,class:"timeline-actions"},Ce={class:"upload-trigger"},be={class:"upload-trigger"},xe={key:1,class:"note-timeline"},Ee={class:"timeline-date"},Ve={class:"timeline-body"},Ne={key:0,class:"timeline-content"},Se={key:1,class:"timeline-images"},De={key:2,class:"timeline-images"},Be={key:0,class:"thumb-wrap"},Ae={key:1,class:"file-wrap"},Pe=["href","title"],Ue={class:"file-name"},W=8e3,ze=ie({__name:"NoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(u,{emit:j}){const c=u,I=j,X=ue(()=>ke(["doctor.appointment/addDoctorNote"])),v=g(!1),C=g(""),N=g(!1),q=ve(),_=t=>q.getImageUrl(t),S=g([]),D=g([]),y=g(0),h=g(0),H=["jpg","jpeg","png","gif","bmp","webp","svg"],B=t=>{var i;const e=((i=t.split(".").pop())==null?void 0:i.toLowerCase().split("?")[0])||"";return H.includes(e)},$=t=>{var i;const e=t.split("/");return decodeURIComponent(((i=e[e.length-1])==null?void 0:i.split("?")[0])||"文件")},K=t=>t.filter(B).map(_),Z=(t,e)=>{const i=t.filter(B),b=t[e];return i.indexOf(b)},J=t=>t?t.split(`
`).filter(Boolean):[],Q=t=>{if(!c.diagnosisId)return;const e=Array.isArray(t)?t:[t];if(e.length<=y.value){y.value=e.length;return}const i=e.slice(y.value);y.value=e.length,i.length>0&&T({diagnosis_id:c.diagnosisId,tongue_images:i}).then(()=>{f.msgSuccess("舌苔照片已添加"),I("refresh")})},Y=t=>{if(!c.diagnosisId)return;const e=Array.isArray(t)?t:[t];if(e.length<=h.value){h.value=e.length;return}const i=e.slice(h.value);h.value=e.length,i.length>0&&T({diagnosis_id:c.diagnosisId,report_files:i}).then(()=>{f.msgSuccess("检查报告已添加"),I("refresh")})};oe(()=>c.notes,()=>{S.value=[],D.value=[],y.value=0,h.value=0});const ee=async()=>{if(!c.diagnosisId){f.msgWarning("当前无诊单,无法添加备注");return}const t=C.value.trim();if(!t){f.msgWarning("请输入备注内容");return}N.value=!0;try{await T({diagnosis_id:c.diagnosisId,content:t}),f.msgSuccess("备注保存成功"),C.value="",v.value=!1,I("refresh")}catch(e){f.msgError((e==null?void 0:e.message)||"保存失败")}finally{N.value=!1}},A=async(t,e,i)=>{try{await ge.confirm("确认删除?","提示",{type:"warning"})}catch{return}await he({note_id:t,image_type:e,image_path:i}),f.msgSuccess("已删除"),I("refresh")};return(t,e)=>{const i=le,b=_e,F=fe,L=me,x=ce,te=ae,se=re,ne=de;return n(),o("div",we,[!u.readonly&&u.diagnosisId?(n(),o("div",Ie,[X.value?(n(),k(i,{key:0,type:"primary",plain:"",size:"small",onClick:e[0]||(e[0]=s=>v.value=!0)},{default:r(()=>[...e[6]||(e[6]=[P(" 添加备注 ",-1)])]),_:1})):m("",!0),l(F,{modelValue:S.value,"onUpdate:modelValue":e[1]||(e[1]=s=>S.value=s),limit:99,type:"image","exclude-domain":!0,onChange:Q},{upload:r(()=>[d("div",Ce,[l(b,{size:20,name:"el-icon-Plus"}),e[7]||(e[7]=d("span",null,"舌苔照片",-1))])]),_:1},8,["modelValue"]),l(F,{modelValue:D.value,"onUpdate:modelValue":e[2]||(e[2]=s=>D.value=s),limit:99,type:"file","exclude-domain":!0,onChange:Y},{upload:r(()=>[d("div",be,[l(b,{size:20,name:"el-icon-Plus"}),e[8]||(e[8]=d("span",null,"检查报告",-1))])]),_:1},8,["modelValue"])])):m("",!0),u.notes.length?(n(),o("div",xe,[(n(!0),o(w,null,E(u.notes,s=>{var R,G;return n(),o("div",{key:s.id,class:"timeline-node"},[e[11]||(e[11]=d("div",{class:"timeline-dot"},null,-1)),d("div",Ee,U(s.note_date),1),d("div",Ve,[s.content?(n(),o("div",Ne,[(n(!0),o(w,null,E(J(s.content),(a,p)=>(n(),o("div",{key:p,class:"content-line"},U(a),1))),128))])):m("",!0),(R=s.tongue_images)!=null&&R.length?(n(),o("div",Se,[e[9]||(e[9]=d("span",{class:"images-label"},"舌苔照片",-1)),(n(!0),o(w,null,E(s.tongue_images,(a,p)=>(n(),o("div",{key:p,class:"thumb-wrap"},[l(L,{src:_(a),"preview-src-list":s.tongue_images.map(_),"initial-index":p,"z-index":W,fit:"cover",class:"timeline-thumb","preview-teleported":""},null,8,["src","preview-src-list","initial-index"]),u.readonly?m("",!0):(n(),k(x,{key:0,class:"thumb-delete",onClick:M(O=>A(s.id,"tongue_images",a),["stop"])},{default:r(()=>[l(V(z))]),_:1},8,["onClick"]))]))),128))])):m("",!0),(G=s.report_files)!=null&&G.length?(n(),o("div",De,[e[10]||(e[10]=d("span",{class:"images-label"},"检查报告",-1)),(n(!0),o(w,null,E(s.report_files,(a,p)=>(n(),o(w,{key:p},[B(a)?(n(),o("div",Be,[l(L,{src:_(a),"preview-src-list":K(s.report_files),"initial-index":Z(s.report_files,p),"z-index":W,fit:"cover",class:"timeline-thumb","preview-teleported":""},null,8,["src","preview-src-list","initial-index"]),u.readonly?m("",!0):(n(),k(x,{key:0,class:"thumb-delete",onClick:M(O=>A(s.id,"report_files",a),["stop"])},{default:r(()=>[l(V(z))]),_:1},8,["onClick"]))])):(n(),o("div",Ae,[d("a",{href:_(a),target:"_blank",class:"file-link",title:$(a)},[l(x,{size:20},{default:r(()=>[l(V(pe))]),_:1}),d("span",Ue,U($(a)),1)],8,Pe),u.readonly?m("",!0):(n(),k(x,{key:0,class:"file-delete",onClick:M(O=>A(s.id,"report_files",a),["stop"])},{default:r(()=>[l(V(z))]),_:1},8,["onClick"]))]))],64))),128))])):m("",!0)])])}),128))])):m("",!0),!u.notes.length&&u.readonly?(n(),k(te,{key:2,description:"暂无备注","image-size":48})):m("",!0),l(ne,{modelValue:v.value,"onUpdate:modelValue":e[5]||(e[5]=s=>v.value=s),title:"添加备注",width:"480px","append-to-body":""},{footer:r(()=>[l(i,{onClick:e[4]||(e[4]=s=>v.value=!1)},{default:r(()=>[...e[12]||(e[12]=[P("取消",-1)])]),_:1}),l(i,{type:"primary",loading:N.value,onClick:ee},{default:r(()=>[...e[13]||(e[13]=[P("保存",-1)])]),_:1},8,["loading"])]),default:r(()=>[l(se,{modelValue:C.value,"onUpdate:modelValue":e[3]||(e[3]=s=>C.value=s),type:"textarea",rows:4,placeholder:"输入今日备注...",maxlength:"500","show-word-limit":""},null,8,["modelValue"])]),_:1},8,["modelValue"])])}}}),Ke=ye(ze,[["__scopeId","data-v-530ad386"]]);export{Ke 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 +1 @@
import{m as I,f as p,a as w}from"./diag-display-DCz_VAqj.js";import{o as y,q as x,r as B,s as e,T as a,u as i,P as N}from"./.pnpm-Dwh6tNxD.js";import{_ as V}from"./index-C9ilrjDr.js";const b={class:"card patient-card"},q={class:"patient-hero"},D={class:"patient-name"},E={class:"patient-meta"},G={key:0},S=y({__name:"PatientInfoCard",props:{apt:{default:()=>({})},diag:{default:()=>({})}},setup(t){return(T,n)=>{var d,s,o,c,m,l,r,g,u,f,h,v,k,P,C;return x(),B("div",b,[n[0]||(n[0]=e("div",{class:"card-title"},"患者信息",-1)),e("div",q,[e("div",D,a(((d=t.apt)==null?void 0:d.patient_name)||"—"),1),e("div",E,[e("div",null,a(i(I)((s=t.apt)==null?void 0:s.patient_phone))+" · "+a(i(p)((o=t.diag)==null?void 0:o.gender))+" · "+a(((c=t.diag)==null?void 0:c.age)!=null?t.diag.age+"岁":"—"),1),e("div",null,a((m=t.diag)!=null&&m.height?t.diag.height+"cm":"—")+" / "+a((l=t.diag)!=null&&l.weight?t.diag.weight+"kg":"—")+" · "+a(((r=t.diag)==null?void 0:r.region)||"—"),1),e("div",null," 预约:"+a((g=t.apt)==null?void 0:g.appointment_date)+" "+a((u=t.apt)==null?void 0:u.appointment_time)+" · "+a(i(w)((f=t.apt)==null?void 0:f.period)),1),e("div",null,"医生:"+a(((h=t.apt)==null?void 0:h.doctor_name)||"—")+" 客服:"+a(((v=t.apt)==null?void 0:v.assistant_name)||"—"),1),e("div",null," 状态:"+a(((k=t.apt)==null?void 0:k.status_desc)||"—")+" · "+a((P=t.apt)!=null&&P.has_prescription?"已开方":"未开方"),1),(C=t.apt)!=null&&C.remark?(x(),B("div",G,"备注:"+a(t.apt.remark),1)):N("",!0)])])])}}}),F=V(S,[["__scopeId","data-v-1b0de09c"]]);export{F as default};
import{m as I,f as p,a as w}from"./diag-display-DCz_VAqj.js";import{o as y,q as x,r as B,s as e,T as a,u as i,P as N}from"./.pnpm-Dwh6tNxD.js";import{_ as V}from"./index-C0Q8AuuZ.js";const b={class:"card patient-card"},q={class:"patient-hero"},D={class:"patient-name"},E={class:"patient-meta"},G={key:0},S=y({__name:"PatientInfoCard",props:{apt:{default:()=>({})},diag:{default:()=>({})}},setup(t){return(T,n)=>{var d,s,o,c,m,l,r,g,u,f,h,v,k,P,C;return x(),B("div",b,[n[0]||(n[0]=e("div",{class:"card-title"},"患者信息",-1)),e("div",q,[e("div",D,a(((d=t.apt)==null?void 0:d.patient_name)||"—"),1),e("div",E,[e("div",null,a(i(I)((s=t.apt)==null?void 0:s.patient_phone))+" · "+a(i(p)((o=t.diag)==null?void 0:o.gender))+" · "+a(((c=t.diag)==null?void 0:c.age)!=null?t.diag.age+"岁":"—"),1),e("div",null,a((m=t.diag)!=null&&m.height?t.diag.height+"cm":"—")+" / "+a((l=t.diag)!=null&&l.weight?t.diag.weight+"kg":"—")+" · "+a(((r=t.diag)==null?void 0:r.region)||"—"),1),e("div",null," 预约:"+a((g=t.apt)==null?void 0:g.appointment_date)+" "+a((u=t.apt)==null?void 0:u.appointment_time)+" · "+a(i(w)((f=t.apt)==null?void 0:f.period)),1),e("div",null,"医生:"+a(((h=t.apt)==null?void 0:h.doctor_name)||"—")+" 客服:"+a(((v=t.apt)==null?void 0:v.assistant_name)||"—"),1),e("div",null," 状态:"+a(((k=t.apt)==null?void 0:k.status_desc)||"—")+" · "+a((P=t.apt)!=null&&P.has_prescription?"已开方":"未开方"),1),(C=t.apt)!=null&&C.remark?(x(),B("div",G,"备注:"+a(t.apt.remark),1)):N("",!0)])])])}}}),F=V(S,[["__scopeId","data-v-1b0de09c"]]);export{F as default};
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{o as L,q as i,r as c,s as d,F as v,O as m,bq as q,D as _,L as k,P as y,G as B,p as f,T as w}from"./.pnpm-Dwh6tNxD.js";import H from"./RecordingVideoPlayer-NZrEWtaq.js";import{e as I,_ as P}from"./index-C9ilrjDr.js";const R={key:0,class:"recording-list"},C={class:"recording-item"},V={key:1,class:"recording-alternates"},N={class:"recording-alternates__links"},D={key:1,class:"text-gray-400"},E=L({__name:"RecordingPlaybackBlock",props:{recordId:{},urls:{}},setup(l){const $=l,h=I(),u=f(()=>{const e=$.urls||[],t=new Set,r=[];for(const o of e){const s=String(o??"").trim();!s||t.has(s)||(t.add(s),r.push(s))}return r}),a=f(()=>{const e=u.value;if(!e.length)return null;const t=e.find(n=>/\.mp4(\?|#|$)/i.test(n));if(t)return t;const r=e.find(n=>/\.m3u8(\?|#|$)/i.test(n)&&/vod-qcloud\.com/i.test(n));if(r)return r;const o=e.find(n=>/\.m3u8(\?|#|$)/i.test(n)&&/\.cos\.[^/]+\.myqcloud\.com/i.test(n));if(o)return o;const s=e.find(n=>/\.m3u8(\?|#|$)/i.test(n));return s||e[0]}),p=f(()=>{const e=u.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=q;return u.value.length?(i(),c("div",R,[d("div",C,[a.value?(i(),c(v,{key:0},[b(a.value)?(i(),m(H,{key:`${l.recordId}-${a.value}`,src:a.value},null,8,["src"])):(i(),m(r,{key:1,href:g(a.value),target:"_blank",type:"primary"},{default:_(()=>[...t[0]||(t[0]=[k(" 打开回放 ",-1)])]),_:1},8,["href"]))],64)):y("",!0),p.value.length?(i(),c("div",V,[t[1]||(t[1]=d("span",{class:"recording-alternates__label"},"备用地址",-1)),d("div",N,[(i(!0),c(v,null,B(p.value,(o,s)=>(i(),m(r,{key:`${l.recordId}-alt-${s}-${o.slice(-32)}`,href:g(o),target:"_blank",type:"primary",class:"recording-alternates__link"},{default:_(()=>[k(w(S(o,s)),1)]),_:2},1032,["href"]))),128))])])):y("",!0)])])):(i(),c("span",D,"暂无"))}}}),x=P(E,[["__scopeId","data-v-d67b2e91"]]);export{x as default};
import{o as L,q as i,r as c,s as d,F as v,O as m,bq as q,D as _,L as k,P as y,G as B,p as f,T as w}from"./.pnpm-Dwh6tNxD.js";import H from"./RecordingVideoPlayer-xuuHPLFC.js";import{e as I,_ as P}from"./index-C0Q8AuuZ.js";const R={key:0,class:"recording-list"},C={class:"recording-item"},V={key:1,class:"recording-alternates"},N={class:"recording-alternates__links"},D={key:1,class:"text-gray-400"},E=L({__name:"RecordingPlaybackBlock",props:{recordId:{},urls:{}},setup(l){const $=l,h=I(),u=f(()=>{const e=$.urls||[],t=new Set,r=[];for(const o of e){const s=String(o??"").trim();!s||t.has(s)||(t.add(s),r.push(s))}return r}),a=f(()=>{const e=u.value;if(!e.length)return null;const t=e.find(n=>/\.mp4(\?|#|$)/i.test(n));if(t)return t;const r=e.find(n=>/\.m3u8(\?|#|$)/i.test(n)&&/vod-qcloud\.com/i.test(n));if(r)return r;const o=e.find(n=>/\.m3u8(\?|#|$)/i.test(n)&&/\.cos\.[^/]+\.myqcloud\.com/i.test(n));if(o)return o;const s=e.find(n=>/\.m3u8(\?|#|$)/i.test(n));return s||e[0]}),p=f(()=>{const e=u.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=q;return u.value.length?(i(),c("div",R,[d("div",C,[a.value?(i(),c(v,{key:0},[b(a.value)?(i(),m(H,{key:`${l.recordId}-${a.value}`,src:a.value},null,8,["src"])):(i(),m(r,{key:1,href:g(a.value),target:"_blank",type:"primary"},{default:_(()=>[...t[0]||(t[0]=[k(" 打开回放 ",-1)])]),_:1},8,["href"]))],64)):y("",!0),p.value.length?(i(),c("div",V,[t[1]||(t[1]=d("span",{class:"recording-alternates__label"},"备用地址",-1)),d("div",N,[(i(!0),c(v,null,B(p.value,(o,s)=>(i(),m(r,{key:`${l.recordId}-alt-${s}-${o.slice(-32)}`,href:g(o),target:"_blank",type:"primary",class:"recording-alternates__link"},{default:_(()=>[k(w(S(o,s)),1)]),_:2},1032,["href"]))),128))])])):y("",!0)])])):(i(),c("span",D,"暂无"))}}}),x=P(E,[["__scopeId","data-v-d67b2e91"]]);export{x as default};
@@ -1,2 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/.pnpm-Dwh6tNxD.js","assets/.pnpm-B3v8nGpq.css"])))=>i.map(i=>d[i]);
import{o as K,ap as z,n as S,R as H,aq as G,q as v,r as p,s as f,ac as O,ad as W,b8 as $,aw as j,F as w,v as k,D as I,u as J,b5 as Q,w as X,P,L as Y,bq as Z,M as _,p as E,al as ee}from"./.pnpm-Dwh6tNxD.js";import{e as ae,_ as ne}from"./index-C9ilrjDr.js";const te={class:"recording-playback__shell"},re=["preload"],oe=["onKeydown"],le=K({__name:"RecordingVideoPlayer",props:{src:{}},setup(B){const V=B,A=ae(),b=_(null),m=_(null),c=_(!1),s=_(!1),t=_(!1);let d=null,r=null,l=0,u=null;function i(){u!==null&&(clearTimeout(u),u=null)}const y=E(()=>{const e=String(V.src||"").trim();return e?N(A.getImageUrl(e)):""}),D=E(()=>{if(!s.value)return"none";const e=y.value;return e&&!L(e)?"metadata":"none"}),q=E(()=>!s.value||t.value);function N(e){if(!e||!/^https?:\/\//i.test(e))return e;try{const a=new URL(e),n=a.hostname.toLowerCase();if(n.includes("myqcloud.com")||n.includes("vod-qcloud.com")||n.includes("vod-qcloud"))return a.pathname.includes("+")&&(a.pathname=a.pathname.replace(/\+/g,"%2B")),a.href}catch{}return e}function L(e){return/\.m3u8(\?|#|$)/i.test(e)}function U(){var n;t.value=!1,i();const e=m.value,a=(n=e==null?void 0:e.error)==null?void 0:n.code;a===MediaError.MEDIA_ERR_ABORTED||a===1||(c.value=!0)}function h(){d&&(d.destroy(),d=null);const e=m.value;e&&(e.pause(),e.removeAttribute("src"),e.load())}function R(e,a){let n=!1;const o=()=>{n||a!==l||(n=!0,i(),t.value=!1)};e.addEventListener("loadedmetadata",()=>o(),{once:!0}),e.addEventListener("loadeddata",()=>o(),{once:!0}),e.addEventListener("canplay",()=>o(),{once:!0}),e.addEventListener("playing",()=>o(),{once:!0}),e.addEventListener("progress",()=>{try{e.buffered.length>0&&e.buffered.end(0)>0&&o("progress-buffered")}catch{}},{passive:!0})}async function g(){if(!s.value)return;await S();const e=m.value,a=y.value;if(!e)return;if(!a){t.value=!1,i();return}const n=++l;if(t.value=!0,i(),h(),c.value=!1,L(a)){try{const o=await ee(()=>import("./.pnpm-Dwh6tNxD.js").then(M=>M.dN),__vite__mapDeps([0,1])),x=o.default;if(x.isSupported()){d=new x({enableWorker:!0,lowLatencyMode:!1,maxBufferLength:20,maxMaxBufferLength:120}),d.on(o.Events.MANIFEST_PARSED,()=>{n===l&&(t.value=!1,i())}),d.on(o.Events.ERROR,(M,F)=>{if(F.fatal){if(n!==l)return;t.value=!1,i(),c.value=!0,h()}}),d.loadSource(a),d.attachMedia(e),u=setTimeout(()=>{u=null,n===l&&t.value&&(t.value=!1)},45e3);return}if(e.canPlayType("application/vnd.apple.mpegurl")){R(e,n),e.src=a,u=setTimeout(()=>{u=null,n===l&&t.value&&(t.value=!1)},45e3);return}}catch{if(n!==l)return;t.value=!1,i(),c.value=!0;return}if(n!==l)return;t.value=!1,i(),c.value=!0;return}R(e,n),e.src=a,u=setTimeout(()=>{u=null,n===l&&t.value&&(t.value=!1)},25e3)}function C(){const e=b.value;if(!e||typeof IntersectionObserver>"u"){s.value=!0,g();return}r=new IntersectionObserver(a=>{for(const n of a)if(n.isIntersecting){r==null||r.disconnect(),r=null,s.value=!0,g();break}},{root:null,rootMargin:"240px 0px",threshold:0}),r.observe(e)}function T(){r==null||r.disconnect(),r=null,s.value||(s.value=!0),g()}return z(()=>{S(()=>{C()})}),H(y,()=>{s.value&&g()}),G(()=>{r==null||r.disconnect(),r=null,i(),l++,h()}),(e,a)=>{const n=X,o=Z;return v(),p("div",{ref_key:"wrapRef",ref:b,class:"recording-playback"},[f("div",te,[O(f("video",{ref_key:"videoRef",ref:m,class:"recording-video",controls:"",playsinline:"","webkit-playsinline":"",preload:D.value,onError:U},null,40,re),[[W,!c.value]]),!c.value&&q.value?(v(),p("div",{key:0,class:"recording-playback__overlay",role:"button",tabindex:"0",onClick:T,onKeydown:$(j(T,["prevent"]),["enter"])},[s.value?(v(),p(w,{key:1},[k(n,{class:"recording-playback__spin"},{default:I(()=>[k(J(Q))]),_:1}),a[2]||(a[2]=f("span",null,"正在加载…",-1))],64)):(v(),p(w,{key:0},[a[0]||(a[0]=f("span",{class:"recording-playback__overlay-title"},"预览待加载",-1)),a[1]||(a[1]=f("span",{class:"recording-playback__overlay-desc"},"滚动至此处将自动加载(减轻并发卡顿),也可点击立即加载",-1))],64))],40,oe)):P("",!0)]),c.value?(v(),p(w,{key:0},[k(o,{href:y.value||"#",target:"_blank",type:"primary"},{default:I(()=>[...a[3]||(a[3]=[Y("在新窗口打开",-1)])]),_:1},8,["href"]),a[4]||(a[4]=f("div",{class:"recording-playback__hint"}," 内嵌播放失败(编码不支持、跨域或私有存储等)时可尝试在新窗口打开。 ",-1))],64)):P("",!0)],512)}}}),ie=ne(le,[["__scopeId","data-v-749b0199"]]);export{ie as default};
import{o as K,ap as z,n as S,R as H,aq as G,q as v,r as p,s as f,ac as O,ad as W,b8 as $,aw as j,F as w,v as k,D as I,u as J,b5 as Q,w as X,P,L as Y,bq as Z,M as _,p as E,al as ee}from"./.pnpm-Dwh6tNxD.js";import{e as ae,_ as ne}from"./index-C0Q8AuuZ.js";const te={class:"recording-playback__shell"},re=["preload"],oe=["onKeydown"],le=K({__name:"RecordingVideoPlayer",props:{src:{}},setup(B){const V=B,A=ae(),b=_(null),m=_(null),c=_(!1),s=_(!1),t=_(!1);let d=null,r=null,l=0,u=null;function i(){u!==null&&(clearTimeout(u),u=null)}const y=E(()=>{const e=String(V.src||"").trim();return e?N(A.getImageUrl(e)):""}),D=E(()=>{if(!s.value)return"none";const e=y.value;return e&&!L(e)?"metadata":"none"}),q=E(()=>!s.value||t.value);function N(e){if(!e||!/^https?:\/\//i.test(e))return e;try{const a=new URL(e),n=a.hostname.toLowerCase();if(n.includes("myqcloud.com")||n.includes("vod-qcloud.com")||n.includes("vod-qcloud"))return a.pathname.includes("+")&&(a.pathname=a.pathname.replace(/\+/g,"%2B")),a.href}catch{}return e}function L(e){return/\.m3u8(\?|#|$)/i.test(e)}function U(){var n;t.value=!1,i();const e=m.value,a=(n=e==null?void 0:e.error)==null?void 0:n.code;a===MediaError.MEDIA_ERR_ABORTED||a===1||(c.value=!0)}function h(){d&&(d.destroy(),d=null);const e=m.value;e&&(e.pause(),e.removeAttribute("src"),e.load())}function R(e,a){let n=!1;const o=()=>{n||a!==l||(n=!0,i(),t.value=!1)};e.addEventListener("loadedmetadata",()=>o(),{once:!0}),e.addEventListener("loadeddata",()=>o(),{once:!0}),e.addEventListener("canplay",()=>o(),{once:!0}),e.addEventListener("playing",()=>o(),{once:!0}),e.addEventListener("progress",()=>{try{e.buffered.length>0&&e.buffered.end(0)>0&&o("progress-buffered")}catch{}},{passive:!0})}async function g(){if(!s.value)return;await S();const e=m.value,a=y.value;if(!e)return;if(!a){t.value=!1,i();return}const n=++l;if(t.value=!0,i(),h(),c.value=!1,L(a)){try{const o=await ee(()=>import("./.pnpm-Dwh6tNxD.js").then(M=>M.dN),__vite__mapDeps([0,1])),x=o.default;if(x.isSupported()){d=new x({enableWorker:!0,lowLatencyMode:!1,maxBufferLength:20,maxMaxBufferLength:120}),d.on(o.Events.MANIFEST_PARSED,()=>{n===l&&(t.value=!1,i())}),d.on(o.Events.ERROR,(M,F)=>{if(F.fatal){if(n!==l)return;t.value=!1,i(),c.value=!0,h()}}),d.loadSource(a),d.attachMedia(e),u=setTimeout(()=>{u=null,n===l&&t.value&&(t.value=!1)},45e3);return}if(e.canPlayType("application/vnd.apple.mpegurl")){R(e,n),e.src=a,u=setTimeout(()=>{u=null,n===l&&t.value&&(t.value=!1)},45e3);return}}catch{if(n!==l)return;t.value=!1,i(),c.value=!0;return}if(n!==l)return;t.value=!1,i(),c.value=!0;return}R(e,n),e.src=a,u=setTimeout(()=>{u=null,n===l&&t.value&&(t.value=!1)},25e3)}function C(){const e=b.value;if(!e||typeof IntersectionObserver>"u"){s.value=!0,g();return}r=new IntersectionObserver(a=>{for(const n of a)if(n.isIntersecting){r==null||r.disconnect(),r=null,s.value=!0,g();break}},{root:null,rootMargin:"240px 0px",threshold:0}),r.observe(e)}function T(){r==null||r.disconnect(),r=null,s.value||(s.value=!0),g()}return z(()=>{S(()=>{C()})}),H(y,()=>{s.value&&g()}),G(()=>{r==null||r.disconnect(),r=null,i(),l++,h()}),(e,a)=>{const n=X,o=Z;return v(),p("div",{ref_key:"wrapRef",ref:b,class:"recording-playback"},[f("div",te,[O(f("video",{ref_key:"videoRef",ref:m,class:"recording-video",controls:"",playsinline:"","webkit-playsinline":"",preload:D.value,onError:U},null,40,re),[[W,!c.value]]),!c.value&&q.value?(v(),p("div",{key:0,class:"recording-playback__overlay",role:"button",tabindex:"0",onClick:T,onKeydown:$(j(T,["prevent"]),["enter"])},[s.value?(v(),p(w,{key:1},[k(n,{class:"recording-playback__spin"},{default:I(()=>[k(J(Q))]),_:1}),a[2]||(a[2]=f("span",null,"正在加载…",-1))],64)):(v(),p(w,{key:0},[a[0]||(a[0]=f("span",{class:"recording-playback__overlay-title"},"预览待加载",-1)),a[1]||(a[1]=f("span",{class:"recording-playback__overlay-desc"},"滚动至此处将自动加载(减轻并发卡顿),也可点击立即加载",-1))],64))],40,oe)):P("",!0)]),c.value?(v(),p(w,{key:0},[k(o,{href:y.value||"#",target:"_blank",type:"primary"},{default:I(()=>[...a[3]||(a[3]=[Y("在新窗口打开",-1)])]),_:1},8,["href"]),a[4]||(a[4]=f("div",{class:"recording-playback__hint"}," 内嵌播放失败(编码不支持、跨域或私有存储等)时可尝试在新窗口打开。 ",-1))],64)):P("",!0)],512)}}}),ie=ne(le,[["__scopeId","data-v-749b0199"]]);export{ie as default};
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
import{o as T,q as e,r as t,v as m,b7 as V,s as d,D as w,L as I,K as E,P as r,F as u,G as v,T as g,O as C,bB as z,M as p}from"./.pnpm-Dwh6tNxD.js";import{a4 as L}from"./tcm-RVDaIW5j.js";import{i as M,_ as S}from"./index-C9ilrjDr.js";/* empty css */const D={class:"tracking-timeline-wrap"},F={key:0,class:"timeline-input"},H={class:"input-actions"},q={key:1,class:"tracking-timeline"},A={class:"timeline-date"},G={class:"timeline-body"},K={key:0,class:"timeline-content"},O=T({__name:"TrackingNoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(n,{emit:f}){const c=n,y=f,o=p(""),l=p(!1),_=s=>s?s.split(`
import{o as T,q as e,r as t,v as m,b7 as V,s as d,D as w,L as I,K as E,P as r,F as u,G as v,T as g,O as C,bB as z,M as p}from"./.pnpm-Dwh6tNxD.js";import{a4 as L}from"./tcm-WWBqr2Vo.js";import{i as M,_ as S}from"./index-C0Q8AuuZ.js";/* empty css */const D={class:"tracking-timeline-wrap"},F={key:0,class:"timeline-input"},H={class:"input-actions"},q={key:1,class:"tracking-timeline"},A={class:"timeline-date"},G={class:"timeline-body"},K={key:0,class:"timeline-content"},O=T({__name:"TrackingNoteTimeline",props:{notes:{},diagnosisId:{},readonly:{type:Boolean}},emits:["refresh"],setup(n,{emit:f}){const c=n,y=f,o=p(""),l=p(!1),_=s=>s?s.split(`
`).filter(Boolean):[],k=async()=>{if(!c.diagnosisId)return;const s=o.value.trim();if(s){l.value=!0;try{await L({diagnosis_id:c.diagnosisId,tracking_content:s}),M.msgSuccess("已添加"),o.value="",y("refresh")}finally{l.value=!1}}};return(s,i)=>{const b=V,h=E,B=z;return e(),t("div",D,[!n.readonly&&n.diagnosisId?(e(),t("div",F,[m(b,{modelValue:o.value,"onUpdate:modelValue":i[0]||(i[0]=a=>o.value=a),type:"textarea",rows:2,placeholder:"输入跟踪备注,回车换行;保存后将以「[HH:MM] 内容」追加到当天记录",maxlength:"1000","show-word-limit":"",resize:"none",disabled:l.value},null,8,["modelValue","disabled"]),d("div",H,[m(h,{type:"primary",size:"small",loading:l.value,disabled:!o.value.trim(),onClick:k},{default:w(()=>[...i[1]||(i[1]=[I(" 添加 ",-1)])]),_:1},8,["loading","disabled"])])])):r("",!0),n.notes.length?(e(),t("div",q,[(e(!0),t(u,null,v(n.notes,a=>(e(),t("div",{key:a.id,class:"timeline-node"},[i[2]||(i[2]=d("div",{class:"timeline-dot"},null,-1)),d("div",A,g(a.note_date),1),d("div",G,[a.content?(e(),t("div",K,[(e(!0),t(u,null,v(_(a.content),(x,N)=>(e(),t("div",{key:N,class:"content-line"},g(x),1))),128))])):r("",!0)])]))),128))])):r("",!0),!n.notes.length&&n.readonly?(e(),C(B,{key:2,description:"暂无跟踪备注","image-size":48})):r("",!0)])}}}),Q=S(O,[["__scopeId","data-v-82b635bd"]]);export{Q as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{_ as o}from"./account-adjust.vue_vue_type_script_setup_true_lang-D0MhgEI6.js";import"./.pnpm-Dwh6tNxD.js";import"./index-BM6NmNnG.js";import"./index-C9ilrjDr.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./account-adjust.vue_vue_type_script_setup_true_lang-BCHVvk0O.js";import"./.pnpm-Dwh6tNxD.js";import"./index-CfJcNX3X.js";import"./index-C0Q8AuuZ.js";export{o as default};
@@ -1 +1 @@
import{o as h,R as v,q,O as B,D as l,s as D,v as t,b9 as F,u as n,b6 as I,L as u,T as w,bc as j,bf as S,b7 as T,a8 as y,ba as U,p as G}from"./.pnpm-Dwh6tNxD.js";import{_ as L}from"./index-BM6NmNnG.js";import{i as V}from"./index-C9ilrjDr.js";const M={class:"pr-8"},H=h({__name:"account-adjust",props:{show:{type:Boolean,required:!0},value:{type:[Number,String],required:!0}},emits:["update:show","confirm"],setup(d,{emit:k}){const s=y(),i=d,f=k,o=U({action:1,num:"",remark:""}),m=y(),c=G(()=>Number(i.value)+Number(o.num)*(o.action==1?1:-1)),R={num:[{required:!0,message:"请输入调整的金额"}]},g=e=>{if(e.includes("-"))return V.msgError("请输入正整数");o.num=e},x=async()=>{var e;await((e=s.value)==null?void 0:e.validate()),f("confirm",o)},E=()=>{var e;f("update:show",!1),(e=s.value)==null||e.resetFields()};return v(()=>i.show,e=>{var a,r;e?(a=m.value)==null||a.open():(r=m.value)==null||r.close()}),v(c,e=>{e<0&&(V.msgError("调整后余额需大于0"),o.num="")}),(e,a)=>{const r=I,_=S,C=j,b=T,N=F;return q(),B(L,{ref_key:"popupRef",ref:m,title:"余额调整",width:"500px",onConfirm:x,async:!0,onClose:E},{default:l(()=>[D("div",M,[t(N,{ref_key:"formRef",ref:s,model:n(o),"label-width":"120px",rules:R},{default:l(()=>[t(r,{label:"当前余额"},{default:l(()=>[u("¥ "+w(d.value),1)]),_:1}),t(r,{label:"余额增减",required:"",prop:"action"},{default:l(()=>[t(C,{modelValue:n(o).action,"onUpdate:modelValue":a[0]||(a[0]=p=>n(o).action=p)},{default:l(()=>[t(_,{value:1},{default:l(()=>[...a[2]||(a[2]=[u("增加余额",-1)])]),_:1}),t(_,{value:2},{default:l(()=>[...a[3]||(a[3]=[u("扣减余额",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),t(r,{label:"调整余额",prop:"num"},{default:l(()=>[t(b,{"model-value":n(o).num,placeholder:"请输入调整的金额",type:"number",onInput:g},null,8,["model-value"])]),_:1}),t(r,{label:"调整后余额"},{default:l(()=>[u(" ¥ "+w(n(c)),1)]),_:1}),t(r,{label:"备注",prop:"remark"},{default:l(()=>[t(b,{modelValue:n(o).remark,"onUpdate:modelValue":a[1]||(a[1]=p=>n(o).remark=p),type:"textarea",rows:4},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])])]),_:1},512)}}});export{H as _};
import{o as h,R as v,q,O as B,D as l,s as D,v as t,b9 as F,u as n,b6 as I,L as u,T as w,bc as j,bf as S,b7 as T,a8 as y,ba as U,p as G}from"./.pnpm-Dwh6tNxD.js";import{_ as L}from"./index-CfJcNX3X.js";import{i as V}from"./index-C0Q8AuuZ.js";const M={class:"pr-8"},H=h({__name:"account-adjust",props:{show:{type:Boolean,required:!0},value:{type:[Number,String],required:!0}},emits:["update:show","confirm"],setup(d,{emit:k}){const s=y(),i=d,f=k,o=U({action:1,num:"",remark:""}),m=y(),c=G(()=>Number(i.value)+Number(o.num)*(o.action==1?1:-1)),R={num:[{required:!0,message:"请输入调整的金额"}]},g=e=>{if(e.includes("-"))return V.msgError("请输入正整数");o.num=e},x=async()=>{var e;await((e=s.value)==null?void 0:e.validate()),f("confirm",o)},E=()=>{var e;f("update:show",!1),(e=s.value)==null||e.resetFields()};return v(()=>i.show,e=>{var a,r;e?(a=m.value)==null||a.open():(r=m.value)==null||r.close()}),v(c,e=>{e<0&&(V.msgError("调整后余额需大于0"),o.num="")}),(e,a)=>{const r=I,_=S,C=j,b=T,N=F;return q(),B(L,{ref_key:"popupRef",ref:m,title:"余额调整",width:"500px",onConfirm:x,async:!0,onClose:E},{default:l(()=>[D("div",M,[t(N,{ref_key:"formRef",ref:s,model:n(o),"label-width":"120px",rules:R},{default:l(()=>[t(r,{label:"当前余额"},{default:l(()=>[u("¥ "+w(d.value),1)]),_:1}),t(r,{label:"余额增减",required:"",prop:"action"},{default:l(()=>[t(C,{modelValue:n(o).action,"onUpdate:modelValue":a[0]||(a[0]=p=>n(o).action=p)},{default:l(()=>[t(_,{value:1},{default:l(()=>[...a[2]||(a[2]=[u("增加余额",-1)])]),_:1}),t(_,{value:2},{default:l(()=>[...a[3]||(a[3]=[u("扣减余额",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),t(r,{label:"调整余额",prop:"num"},{default:l(()=>[t(b,{"model-value":n(o).num,placeholder:"请输入调整的金额",type:"number",onInput:g},null,8,["model-value"])]),_:1}),t(r,{label:"调整后余额"},{default:l(()=>[u(" ¥ "+w(n(c)),1)]),_:1}),t(r,{label:"备注",prop:"remark"},{default:l(()=>[t(b,{modelValue:n(o).remark,"onUpdate:modelValue":a[1]||(a[1]=p=>n(o).remark=p),type:"textarea",rows:4},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])])]),_:1},512)}}});export{H as _};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
import{_ as o}from"./add-nav.vue_vue_type_script_setup_true_lang-CH8U6Lyn.js";import"./.pnpm-Dwh6tNxD.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./add-nav.vue_vue_type_script_setup_true_lang-D73JnCTp.js";import"./.pnpm-Dwh6tNxD.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -1 +1 @@
import{o as E,q as p,r as C,s as l,v as a,u as c,bQ as B,C as N,D as d,O as $,b7 as z,b6 as D,I,K as A,L,p as R}from"./.pnpm-Dwh6tNxD.js";import{_ as q}from"./index-4fo3NoYp.js";import{_ as F}from"./picker-K9bQMD5v.js";import{_ as K}from"./picker-DYD_beSt.js";import{c as O,i as r}from"./index-C9ilrjDr.js";const P={class:"bg-fill-light flex items-center w-full p-4 mb-4"},Q={class:"upload-btn w-[60px] h-[60px]"},S={class:"ml-3 flex-1"},T={class:"flex items-center"},j={class:"flex items-center mt-[18px]"},G={class:"flex-1 flex items-center"},H={class:"drag-move cursor-move ml-auto"},Z=E({__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=R({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}`)},v=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 u=O,g=K,b=z,h=F,k=I,w=D,y=q,U=A;return p(),C("div",null,[l("div",null,[a(c(B),{class:"draggable",modelValue:c(m),"onUpdate:modelValue":e[0]||(e[0]=o=>N(m)?m.value=o:null),animation:"300",handle:".drag-move","item-key":"index"},{item:d(({element:o,index:i})=>[(p(),$(y,{class:"w-[467px]",key:i,onClose:n=>v(i)},{default:d(()=>[l("div",P,[a(g,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body",size:"60px","exclude-domain":""},{upload:d(()=>[l("div",Q,[a(u,{name:"el-icon-Plus",size:20})])]),_:1},8,["modelValue","onUpdate:modelValue"]),l("div",S,[l("div",T,[e[1]||(e[1]=l("span",{class:"text-tx-regular flex-none mr-3"},"名称",-1)),a(b,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),l("div",j,[e[2]||(e[2]=l("span",{class:"text-tx-regular flex-none mr-3"},"链接",-1)),a(h,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),a(w,{label:"是否显示",class:"mt-[18px]"},{default:d(()=>[l("div",G,[a(k,{modelValue:o.is_show,"onUpdate:modelValue":n=>o.is_show=n,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),l("div",H,[a(u,{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]=[L("添加",-1)])]),_:1})])])}}});export{Z as _};
import{o as E,q as p,r as C,s as l,v as a,u as c,bQ as B,C as N,D as d,O as $,b7 as z,b6 as D,I,K as A,L,p as R}from"./.pnpm-Dwh6tNxD.js";import{_ as q}from"./index-39SS-XKl.js";import{_ as F}from"./picker-D3OnL1mV.js";import{_ as K}from"./picker-2bpe8Dva.js";import{c as O,i as r}from"./index-C0Q8AuuZ.js";const P={class:"bg-fill-light flex items-center w-full p-4 mb-4"},Q={class:"upload-btn w-[60px] h-[60px]"},S={class:"ml-3 flex-1"},T={class:"flex items-center"},j={class:"flex items-center mt-[18px]"},G={class:"flex-1 flex items-center"},H={class:"drag-move cursor-move ml-auto"},Z=E({__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=R({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}`)},v=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 u=O,g=K,b=z,h=F,k=I,w=D,y=q,U=A;return p(),C("div",null,[l("div",null,[a(c(B),{class:"draggable",modelValue:c(m),"onUpdate:modelValue":e[0]||(e[0]=o=>N(m)?m.value=o:null),animation:"300",handle:".drag-move","item-key":"index"},{item:d(({element:o,index:i})=>[(p(),$(y,{class:"w-[467px]",key:i,onClose:n=>v(i)},{default:d(()=>[l("div",P,[a(g,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body",size:"60px","exclude-domain":""},{upload:d(()=>[l("div",Q,[a(u,{name:"el-icon-Plus",size:20})])]),_:1},8,["modelValue","onUpdate:modelValue"]),l("div",S,[l("div",T,[e[1]||(e[1]=l("span",{class:"text-tx-regular flex-none mr-3"},"名称",-1)),a(b,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),l("div",j,[e[2]||(e[2]=l("span",{class:"text-tx-regular flex-none mr-3"},"链接",-1)),a(h,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),a(w,{label:"是否显示",class:"mt-[18px]"},{default:d(()=>[l("div",G,[a(k,{modelValue:o.is_show,"onUpdate:modelValue":n=>o.is_show=n,"active-value":"1","inactive-value":"0"},null,8,["modelValue","onUpdate:modelValue"]),l("div",H,[a(u,{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]=[L("添加",-1)])]),_:1})])])}}});export{Z as _};
@@ -1 +1 @@
import{r as n}from"./index-C9ilrjDr.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-C0Q8AuuZ.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-C9ilrjDr.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-C0Q8AuuZ.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{r as e}from"./index-C9ilrjDr.js";function r(s){return e.get({url:"/asset.AssetUser/lists",params:s})}function u(s){return e.post({url:"/asset.AssetUser/add",params:s})}function a(s){return e.post({url:"/asset.AssetUser/edit",params:s})}function i(s){return e.post({url:"/asset.AssetUser/delete",params:s})}function o(s){return e.get({url:"/asset.AssetResource/lists",params:s})}function n(s){return e.post({url:"/asset.AssetResource/add",params:s})}function A(s){return e.post({url:"/asset.AssetResource/edit",params:s})}function c(s){return e.post({url:"/asset.AssetResource/delete",params:s})}export{o as a,c as b,A as c,n as d,r as e,a as f,i as g,u as h};
import{r as e}from"./index-C0Q8AuuZ.js";function r(s){return e.get({url:"/asset.AssetUser/lists",params:s})}function u(s){return e.post({url:"/asset.AssetUser/add",params:s})}function a(s){return e.post({url:"/asset.AssetUser/edit",params:s})}function i(s){return e.post({url:"/asset.AssetUser/delete",params:s})}function o(s){return e.get({url:"/asset.AssetResource/lists",params:s})}function n(s){return e.post({url:"/asset.AssetResource/add",params:s})}function A(s){return e.post({url:"/asset.AssetResource/edit",params:s})}function c(s){return e.post({url:"/asset.AssetResource/delete",params:s})}export{o as a,c as b,A as c,n as d,r as e,a as f,i as g,u as h};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-Cbk2Xa5e.js";import"./.pnpm-Dwh6tNxD.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-Ctu7ajT8.js";import"./.pnpm-Dwh6tNxD.js";import"./add-nav.vue_vue_type_script_setup_true_lang-D73JnCTp.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-DwnFVvmv.js";import"./.pnpm-Dwh6tNxD.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-2Q5vVd2y.js";import"./.pnpm-Dwh6tNxD.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-BLTWBJHy.js";import"./.pnpm-Dwh6tNxD.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-BX-tcO7M.js";import"./.pnpm-Dwh6tNxD.js";import"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";import"./picker-2bpe8Dva.js";import"./index-CfJcNX3X.js";import"./index-C0Q8AuuZ.js";import"./index-B-j4AceK.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./index-39SS-XKl.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./usePaging-DOuAwzL9.js";export{o as default};
@@ -1 +1 @@
import{o as b,q as c,r as V,s as v,v as t,D as a,Y as x,X as E,u as l,b9 as g,F as k,p as w}from"./.pnpm-Dwh6tNxD.js";import{_ as p}from"./menu-set.vue_vue_type_script_setup_true_lang-BwM2_EVX.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";const $=b({__name:"attr",props:{modelValue:{type:Object,default:()=>({nav:[],menu:{}})}},emits:["update:modelValue"],setup(s,{emit:u}){const d=s,i=u,o=w({get(){return d.modelValue},set(n){i("update:modelValue",n)}});return(n,e)=>{const r=E,f=x,_=g;return c(),V(k,null,[e[2]||(e[2]=v("div",{class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2"}," pc导航设置 ",-1)),t(_,{class:"mt-4","label-width":"70px"},{default:a(()=>[t(f,{"model-value":"nav"},{default:a(()=>[t(r,{label:"主导航设置",name:"nav"},{default:a(()=>[t(p,{modelValue:l(o).nav,"onUpdate:modelValue":e[0]||(e[0]=m=>l(o).nav=m)},null,8,["modelValue"])]),_:1}),t(r,{label:"菜单设置",name:"menu"},{default:a(()=>[t(p,{modelValue:l(o).menu,"onUpdate:modelValue":e[1]||(e[1]=m=>l(o).menu=m)},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})],64)}}});export{$ as default};
import{o as b,q as c,r as V,s as v,v as t,D as a,Y as x,X as E,u as l,b9 as g,F as k,p as w}from"./.pnpm-Dwh6tNxD.js";import{_ as p}from"./menu-set.vue_vue_type_script_setup_true_lang-BLwvkWQS.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";const $=b({__name:"attr",props:{modelValue:{type:Object,default:()=>({nav:[],menu:{}})}},emits:["update:modelValue"],setup(s,{emit:u}){const d=s,i=u,o=w({get(){return d.modelValue},set(n){i("update:modelValue",n)}});return(n,e)=>{const r=E,f=x,_=g;return c(),V(k,null,[e[2]||(e[2]=v("div",{class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2"}," pc导航设置 ",-1)),t(_,{class:"mt-4","label-width":"70px"},{default:a(()=>[t(f,{"model-value":"nav"},{default:a(()=>[t(r,{label:"主导航设置",name:"nav"},{default:a(()=>[t(p,{modelValue:l(o).nav,"onUpdate:modelValue":e[0]||(e[0]=m=>l(o).nav=m)},null,8,["modelValue"])]),_:1}),t(r,{label:"菜单设置",name:"menu"},{default:a(()=>[t(p,{modelValue:l(o).menu,"onUpdate:modelValue":e[1]||(e[1]=m=>l(o).menu=m)},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})],64)}}});export{$ as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-C0LPpfEu.js";import"./.pnpm-Dwh6tNxD.js";import"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";import"./picker-DYD_beSt.js";import"./index-BM6NmNnG.js";import"./index-C9ilrjDr.js";import"./index-DB4KfTa0.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./index-4fo3NoYp.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./usePaging-DOuAwzL9.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-B28CVUAq.js";import"./.pnpm-Dwh6tNxD.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-DyoPs8TD.js";import"./.pnpm-Dwh6tNxD.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-B6uHrbrS.js";import"./.pnpm-Dwh6tNxD.js";import"./add-nav.vue_vue_type_script_setup_true_lang-CH8U6Lyn.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-BEJoSc1o.js";import"./.pnpm-Dwh6tNxD.js";import"./picker-2bpe8Dva.js";import"./index-CfJcNX3X.js";import"./index-C0Q8AuuZ.js";import"./index-B-j4AceK.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./index-39SS-XKl.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./usePaging-DOuAwzL9.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-C-c-r9RC.js";import"./.pnpm-Dwh6tNxD.js";import"./picker-DYD_beSt.js";import"./index-BM6NmNnG.js";import"./index-C9ilrjDr.js";import"./index-DB4KfTa0.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./index-4fo3NoYp.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./usePaging-DOuAwzL9.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-Vz3txZfV.js";import"./.pnpm-Dwh6tNxD.js";import"./add-nav.vue_vue_type_script_setup_true_lang-CH8U6Lyn.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr.vue_vue_type_script_setup_true_lang-CxVBLyr-.js";import"./.pnpm-Dwh6tNxD.js";import"./add-nav.vue_vue_type_script_setup_true_lang-D73JnCTp.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./attr-setting.vue_vue_type_script_setup_true_lang-x-XafvgN.js";import"./.pnpm-Dwh6tNxD.js";import"./index-LzaTAqVs.js";import"./attr-CcBlHQ6U.js";import"./index-39SS-XKl.js";import"./index-C0Q8AuuZ.js";import"./picker-D3OnL1mV.js";import"./index-CfJcNX3X.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-B7li-XJN.js";import"./usePaging-DOuAwzL9.js";import"./picker-2bpe8Dva.js";import"./index-B-j4AceK.js";import"./index-4SRyrKER.js";import"./file-BUuEowhq.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./content.vue_vue_type_script_setup_true_lang-67HcMoa-.js";import"./decoration-img-g1NB8PSI.js";import"./attr.vue_vue_type_script_setup_true_lang-BEJoSc1o.js";import"./content-CqaVEK4f.js";import"./attr.vue_vue_type_script_setup_true_lang-2Q5vVd2y.js";import"./content.vue_vue_type_script_setup_true_lang-BQxNT8cz.js";import"./attr.vue_vue_type_script_setup_true_lang-Vz3txZfV.js";import"./add-nav.vue_vue_type_script_setup_true_lang-CH8U6Lyn.js";import"./content-qYVlkYgK.js";import"./attr.vue_vue_type_script_setup_true_lang-B6uHrbrS.js";import"./content.vue_vue_type_script_setup_true_lang-Dpn7S-bh.js";import"./attr.vue_vue_type_script_setup_true_lang--WwiPUCL.js";import"./content-DytPruqB.js";import"./decoration-BcG7z9u1.js";import"./attr.vue_vue_type_script_setup_true_lang-BX-tcO7M.js";import"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";import"./content-BI4DYec0.js";import"./content.vue_vue_type_script_setup_true_lang-v-Of3bVR.js";import"./attr.vue_vue_type_script_setup_true_lang-B4PfotVc.js";import"./content-wxLxJxNK.js";import"./attr.vue_vue_type_script_setup_true_lang-DwnFVvmv.js";import"./content.vue_vue_type_script_setup_true_lang-BDl5oRtm.js";import"./attr.vue_vue_type_script_setup_true_lang-BJHLs4e8.js";import"./content-DzwjOGpc.js";export{o as default};
@@ -1 +0,0 @@
import{_ as o}from"./attr-setting.vue_vue_type_script_setup_true_lang-C6DcKNDl.js";import"./.pnpm-Dwh6tNxD.js";import"./index-Z-zCbKBZ.js";import"./attr-CR6HHmCW.js";import"./index-4fo3NoYp.js";import"./index-C9ilrjDr.js";import"./picker-K9bQMD5v.js";import"./index-BM6NmNnG.js";import"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import"./article-C6Uwi7c8.js";import"./usePaging-DOuAwzL9.js";import"./picker-DYD_beSt.js";import"./index-DB4KfTa0.js";import"./index-DBhmZUba.js";import"./file-CNQVkxcM.js";import"./index.vue_vue_type_script_setup_true_lang-Cxx3Fcm2.js";import"./content.vue_vue_type_script_setup_true_lang-Dr8Z9LMW.js";import"./decoration-img-B97_laTE.js";import"./attr.vue_vue_type_script_setup_true_lang-C-c-r9RC.js";import"./content-CqZOVZ6z.js";import"./attr.vue_vue_type_script_setup_true_lang-BLTWBJHy.js";import"./content.vue_vue_type_script_setup_true_lang-B-U8T_iq.js";import"./attr.vue_vue_type_script_setup_true_lang-Ctu7ajT8.js";import"./add-nav.vue_vue_type_script_setup_true_lang-D73JnCTp.js";import"./content-CAhICNVX.js";import"./attr.vue_vue_type_script_setup_true_lang-CxVBLyr-.js";import"./content.vue_vue_type_script_setup_true_lang-QVsMdosa.js";import"./attr.vue_vue_type_script_setup_true_lang--WwiPUCL.js";import"./content-B0IFiMrg.js";import"./decoration-C0nTh_VL.js";import"./attr.vue_vue_type_script_setup_true_lang-C0LPpfEu.js";import"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";import"./content-DMHFaAWx.js";import"./content.vue_vue_type_script_setup_true_lang-BjvjVaXz.js";import"./attr.vue_vue_type_script_setup_true_lang-B4PfotVc.js";import"./content-3pdJCc10.js";import"./attr.vue_vue_type_script_setup_true_lang-Cbk2Xa5e.js";import"./content.vue_vue_type_script_setup_true_lang-ClT1-8Uj.js";import"./attr.vue_vue_type_script_setup_true_lang-BJHLs4e8.js";import"./content-B7paQOYI.js";export{o as default};
@@ -1 +1 @@
import{o as g,q as a,r as b,v as c,bg as y,D as r,s as x,T as _,a2 as h,O as i,a3 as w,a4 as v,u as C}from"./.pnpm-Dwh6tNxD.js";import{e as k}from"./index-Z-zCbKBZ.js";const B={class:"pages-setting"},D={class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2 text-xl font-medium"},O=g({__name:"attr-setting",props:{widget:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(e,{emit:d}){const m=d,p=n=>{m("update:content",n)};return(n,E)=>{const f=y,u=h;return a(),b("div",B,[c(f,{shadow:"never",class:"!border-none flex"},{default:r(()=>{var t;return[x("div",D,_((t=e.widget)==null?void 0:t.title),1)]}),_:1}),c(u,{class:"w-full",style:{height:"calc(100% - 60px)"}},{default:r(()=>{var t,s,o,l;return[(a(),i(w,null,[(a(),i(v((s=C(k)[(t=e.widget)==null?void 0:t.name])==null?void 0:s.attr),{content:(o=e.widget)==null?void 0:o.content,styles:(l=e.widget)==null?void 0:l.styles,type:e.type,"onUpdate:content":p},null,40,["content","styles","type"]))],1024))]}),_:1})])}}});export{O as _};
import{o as g,q as a,r as b,v as c,bg as y,D as r,s as x,T as _,a2 as h,O as i,a3 as w,a4 as v,u as C}from"./.pnpm-Dwh6tNxD.js";import{e as k}from"./index-LzaTAqVs.js";const B={class:"pages-setting"},D={class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2 text-xl font-medium"},O=g({__name:"attr-setting",props:{widget:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(e,{emit:d}){const m=d,p=n=>{m("update:content",n)};return(n,E)=>{const f=y,u=h;return a(),b("div",B,[c(f,{shadow:"never",class:"!border-none flex"},{default:r(()=>{var t;return[x("div",D,_((t=e.widget)==null?void 0:t.title),1)]}),_:1}),c(u,{class:"w-full",style:{height:"calc(100% - 60px)"}},{default:r(()=>{var t,s,o,l;return[(a(),i(w,null,[(a(),i(v((s=C(k)[(t=e.widget)==null?void 0:t.name])==null?void 0:s.attr),{content:(o=e.widget)==null?void 0:o.content,styles:(l=e.widget)==null?void 0:l.styles,type:e.type,"onUpdate:content":p},null,40,["content","styles","type"]))],1024))]}),_:1})])}}});export{O as _};
@@ -1 +1 @@
import{o as j,q as d,r as b,v as o,D as s,bg as F,s as n,u as p,bQ as S,O as _,b6 as q,P as r,b7 as z,I as A,K,L,b9 as P,p as Q,cm as v}from"./.pnpm-Dwh6tNxD.js";import{_ as R}from"./index-4fo3NoYp.js";import{c as T,i as k}from"./index-C9ilrjDr.js";import{_ as G}from"./picker-K9bQMD5v.js";import{_ as H}from"./picker-DYD_beSt.js";const J={class:"flex-1"},M={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,ae=j({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(m,{emit:y}){const u=y,c=m,g=Q({get:()=>c.content,set:a=>{u("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:{}}),u("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),u("update:content",e)};return(a,e)=>{const i=H,U=G,C=z,h=q,B=A,D=T,N=R,$=K,I=F,O=P;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",J,[o(p(S),{class:"draggable",modelValue:p(g).data,"onUpdate:modelValue":e[0]||(e[0]=t=>p(g).data=t),animation:"300",handle:".drag-move"},{item:s(({element:t,index:V})=>[(d(),_(N,{key:V,onClose:l=>E(V),class:"w-full"},{default:s(()=>[n("div",M,[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,{key:0,modelValue:t.link,"onUpdate:modelValue":l=>t.link=l},null,8,["modelValue","onUpdate:modelValue"])):r("",!0),m.type=="pc"?(d(),_(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{ae as _};
import{o as j,q as d,r as b,v as o,D as s,bg as F,s as n,u as p,bQ as S,O as _,b6 as q,P as r,b7 as z,I as A,K,L,b9 as P,p as Q,cm as v}from"./.pnpm-Dwh6tNxD.js";import{_ as R}from"./index-39SS-XKl.js";import{c as T,i as k}from"./index-C0Q8AuuZ.js";import{_ as G}from"./picker-D3OnL1mV.js";import{_ as H}from"./picker-2bpe8Dva.js";const J={class:"flex-1"},M={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,ae=j({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})},type:{type:String,default:"mobile"}},emits:["update:content"],setup(m,{emit:y}){const u=y,c=m,g=Q({get:()=>c.content,set:a=>{u("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:{}}),u("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),u("update:content",e)};return(a,e)=>{const i=H,U=G,C=z,h=q,B=A,D=T,N=R,$=K,I=F,O=P;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",J,[o(p(S),{class:"draggable",modelValue:p(g).data,"onUpdate:modelValue":e[0]||(e[0]=t=>p(g).data=t),animation:"300",handle:".drag-move"},{item:s(({element:t,index:V})=>[(d(),_(N,{key:V,onClose:l=>E(V),class:"w-full"},{default:s(()=>[n("div",M,[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,{key:0,modelValue:t.link,"onUpdate:modelValue":l=>t.link=l},null,8,["modelValue","onUpdate:modelValue"])):r("",!0),m.type=="pc"?(d(),_(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{ae as _};
@@ -1 +1 @@
import{o as k,q as d,r as u,v as l,D as o,bg as F,s,bc as U,u as n,bf as B,L as x,b6 as C,bm as N,F as b,G as c,bn as O,b9 as j,p as D}from"./.pnpm-Dwh6tNxD.js";import{_ as G}from"./add-nav.vue_vue_type_script_setup_true_lang-D73JnCTp.js";const L={class:"flex-1 mt-4"},I=k({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(v,{emit:V}){const y=V,w=v,a=D({get:()=>w.content,set:m=>{y("update:content",m)}});return(m,e)=>{const r=B,E=U,p=O,_=N,i=C,f=F,g=j;return d(),u("div",null,[l(g,{"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(i,{label:"每行数量",class:"mt-4"},{default:o(()=>[l(_,{modelValue:n(a).per_line,"onUpdate:modelValue":e[1]||(e[1]=t=>n(a).per_line=t),style:{width:"300px"}},{default:o(()=>[(d(),u(b,null,c(5,t=>l(p,{key:t,label:t+"个",value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"])]),_:1}),l(i,{label:"显示行数"},{default:o(()=>[l(_,{modelValue:n(a).show_line,"onUpdate:modelValue":e[2]||(e[2]=t=>n(a).show_line=t),style:{width:"300px"}},{default:o(()=>[(d(),u(b,null,c(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",L,[l(G,{modelValue:n(a).data,"onUpdate:modelValue":e[3]||(e[3]=t=>n(a).data=t)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{I as _};
import{o as k,q as d,r as u,v as l,D as o,bg as F,s,bc as U,u as n,bf as B,L as x,b6 as C,bm as N,F as b,G as c,bn as O,b9 as j,p as D}from"./.pnpm-Dwh6tNxD.js";import{_ as G}from"./add-nav.vue_vue_type_script_setup_true_lang-CH8U6Lyn.js";const L={class:"flex-1 mt-4"},I=k({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(v,{emit:V}){const y=V,w=v,a=D({get:()=>w.content,set:m=>{y("update:content",m)}});return(m,e)=>{const r=B,E=U,p=O,_=N,i=C,f=F,g=j;return d(),u("div",null,[l(g,{"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(i,{label:"每行数量",class:"mt-4"},{default:o(()=>[l(_,{modelValue:n(a).per_line,"onUpdate:modelValue":e[1]||(e[1]=t=>n(a).per_line=t),style:{width:"300px"}},{default:o(()=>[(d(),u(b,null,c(5,t=>l(p,{key:t,label:t+"个",value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"])]),_:1}),l(i,{label:"显示行数"},{default:o(()=>[l(_,{modelValue:n(a).show_line,"onUpdate:modelValue":e[2]||(e[2]=t=>n(a).show_line=t),style:{width:"300px"}},{default:o(()=>[(d(),u(b,null,c(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",L,[l(G,{modelValue:n(a).data,"onUpdate:modelValue":e[3]||(e[3]=t=>n(a).data=t)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{I as _};
@@ -1 +1 @@
import{o as V,q as b,r as w,v as e,D as n,bg as x,b6 as g,b7 as k,u as o,s as E,b9 as U,p as v}from"./.pnpm-Dwh6tNxD.js";import{_ as q}from"./picker-DYD_beSt.js";const C=V({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(u,{emit:p}){const r=p,i=u,l=v({get:()=>i.content,set:d=>{r("update:content",d)}});return(d,t)=>{const s=k,m=g,_=q,c=x,f=U;return b(),w("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(()=>[E("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{C as _};
import{o as V,q as b,r as w,v as e,D as n,bg as x,b6 as g,b7 as k,u as o,s as E,b9 as U,p as v}from"./.pnpm-Dwh6tNxD.js";import{_ as q}from"./picker-2bpe8Dva.js";const C=V({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(u,{emit:p}){const r=p,i=u,l=v({get:()=>i.content,set:d=>{r("update:content",d)}});return(d,t)=>{const s=k,m=g,_=q,c=x,f=U;return b(),w("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(()=>[E("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{C as _};
@@ -1 +1 @@
import{o as E,q as s,O as r,D as t,v as l,bg as F,b6 as C,bc as N,u as a,bf as z,L as p,b7 as B,P as i,s as b,b9 as O,p as j}from"./.pnpm-Dwh6tNxD.js";import{_ as D}from"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";import{_ as I}from"./picker-DYD_beSt.js";const G=E({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(d,{emit:g}){const y=g,x=d,o=j({get:()=>x.content,set:f=>{y("update:content",f)}});return(f,e)=>{const m=z,_=N,u=C,v=B,V=I,k=D,U=F,w=O;return s(),r(w,{ref:"form","label-width":"80px",size:"large"},{default:t(()=>[l(U,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>[l(u,{label:"页面标题"},{default:t(()=>[l(_,{modelValue:a(o).title_type,"onUpdate:modelValue":e[0]||(e[0]=n=>a(o).title_type=n)},{default:t(()=>[l(m,{value:"1"},{default:t(()=>[...e[7]||(e[7]=[p("文字",-1)])]),_:1}),l(m,{value:"2"},{default:t(()=>[...e[8]||(e[8]=[p("图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),d.content.title_type==1?(s(),r(u,{key:0},{default:t(()=>[l(v,{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),d.content.title_type==2?(s(),r(u,{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]=b("div",{class:"form-tips"},"建议图片尺寸:300px*40px",-1))]),_:1})):i("",!0),d.content.title_type==1?(s(),r(u,{key:2,label:"文字颜色"},{default:t(()=>[l(_,{modelValue:a(o).text_color,"onUpdate:modelValue":e[3]||(e[3]=n=>a(o).text_color=n)},{default:t(()=>[l(m,{value:"1"},{default:t(()=>[...e[10]||(e[10]=[p("白色",-1)])]),_:1}),l(m,{value:"2"},{default:t(()=>[...e[11]||(e[11]=[p("黑色",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1})):i("",!0),l(u,{label:"页面背景"},{default:t(()=>[l(_,{modelValue:a(o).bg_type,"onUpdate:modelValue":e[4]||(e[4]=n=>a(o).bg_type=n)},{default:t(()=>[l(m,{value:"1"},{default:t(()=>[...e[12]||(e[12]=[p("背景颜色",-1)])]),_:1}),l(m,{value:"2"},{default:t(()=>[...e[13]||(e[13]=[p("背景图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),d.content.bg_type==1?(s(),r(u,{key:3},{default:t(()=>[l(k,{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),d.content.bg_type==2?(s(),r(u,{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]=b("div",{class:"form-tips"},"建议图片尺寸:750px*高度不限",-1))]),_:1})):i("",!0)]),_:1})]),_:1},512)}}});export{G as _};
import{o as E,q as s,O as r,D as t,v as l,bg as F,b6 as C,bc as N,u as a,bf as z,L as p,b7 as B,P as i,s as b,b9 as O,p as j}from"./.pnpm-Dwh6tNxD.js";import{_ as D}from"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";import{_ as I}from"./picker-2bpe8Dva.js";const G=E({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(d,{emit:g}){const y=g,x=d,o=j({get:()=>x.content,set:f=>{y("update:content",f)}});return(f,e)=>{const m=z,_=N,u=C,v=B,V=I,k=D,U=F,w=O;return s(),r(w,{ref:"form","label-width":"80px",size:"large"},{default:t(()=>[l(U,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>[l(u,{label:"页面标题"},{default:t(()=>[l(_,{modelValue:a(o).title_type,"onUpdate:modelValue":e[0]||(e[0]=n=>a(o).title_type=n)},{default:t(()=>[l(m,{value:"1"},{default:t(()=>[...e[7]||(e[7]=[p("文字",-1)])]),_:1}),l(m,{value:"2"},{default:t(()=>[...e[8]||(e[8]=[p("图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),d.content.title_type==1?(s(),r(u,{key:0},{default:t(()=>[l(v,{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),d.content.title_type==2?(s(),r(u,{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]=b("div",{class:"form-tips"},"建议图片尺寸:300px*40px",-1))]),_:1})):i("",!0),d.content.title_type==1?(s(),r(u,{key:2,label:"文字颜色"},{default:t(()=>[l(_,{modelValue:a(o).text_color,"onUpdate:modelValue":e[3]||(e[3]=n=>a(o).text_color=n)},{default:t(()=>[l(m,{value:"1"},{default:t(()=>[...e[10]||(e[10]=[p("白色",-1)])]),_:1}),l(m,{value:"2"},{default:t(()=>[...e[11]||(e[11]=[p("黑色",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1})):i("",!0),l(u,{label:"页面背景"},{default:t(()=>[l(_,{modelValue:a(o).bg_type,"onUpdate:modelValue":e[4]||(e[4]=n=>a(o).bg_type=n)},{default:t(()=>[l(m,{value:"1"},{default:t(()=>[...e[12]||(e[12]=[p("背景颜色",-1)])]),_:1}),l(m,{value:"2"},{default:t(()=>[...e[13]||(e[13]=[p("背景图片",-1)])]),_:1})]),_:1},8,["modelValue"])]),_:1}),d.content.bg_type==1?(s(),r(u,{key:3},{default:t(()=>[l(k,{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),d.content.bg_type==2?(s(),r(u,{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]=b("div",{class:"form-tips"},"建议图片尺寸:750px*高度不限",-1))]),_:1})):i("",!0)]),_:1})]),_:1},512)}}});export{G as _};
@@ -1 +1 @@
import{o as I,q as i,r as g,v as t,D as l,bg as O,s,u,bQ as j,O as F,b6 as q,b7 as z,I as A,K,L,P,b9 as Q,p as R,cm as b}from"./.pnpm-Dwh6tNxD.js";import{_ as S}from"./index-4fo3NoYp.js";import{c as T,i as v}from"./index-C9ilrjDr.js";import{_ as G}from"./picker-K9bQMD5v.js";import{_ as H}from"./picker-DYD_beSt.js";const J={class:"bg-fill-light flex items-center w-full p-4 mt-4"},M={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"},p=5,le=I({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(r,{emit:h}){const m=h,c=r,f=R({get:()=>c.content,set:a=>{m("update:content",a)}}),k=()=>{var a;if(((a=c.content.data)==null?void 0:a.length)<p){const e=b(c.content);e.data.push({is_show:"1",image:"",name:"",link:{}}),m("update:content",e)}else v.msgError(`最多添加${p}张图片`)},w=a=>{var d;if(((d=c.content.data)==null?void 0:d.length)<=1)return v.msgError("最少保留一张图片");const e=b(c.content);e.data.splice(a,1),m("update:content",e)};return(a,e)=>{const d=H,y=z,_=q,E=G,U=A,C=T,B=S,D=K,N=O,$=Q;return i(),g("div",null,[t($,{"label-width":"70px"},{default:l(()=>[t(N,{shadow:"never",class:"!border-none flex mt-2"},{default:l(()=>{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(u(j),{class:"draggable",modelValue:u(f).data,"onUpdate:modelValue":e[0]||(e[0]=o=>u(f).data=o),animation:"300",handle:".drag-move","item-key":"index"},{item:l(({element:o,index:V})=>[(i(),F(B,{key:V,onClose:n=>w(V),class:"w-[467px]"},{default:l(()=>[s("div",J,[t(d,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body","exclude-domain":""},null,8,["modelValue","onUpdate:modelValue"]),s("div",M,[t(_,{label:"图片名称"},{default:l(()=>[t(y,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(_,{class:"mt-[18px]",label:"图片链接"},{default:l(()=>[t(E,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(_,{label:"是否显示",class:"mt-[18px]"},{default:l(()=>[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=r.content.data)==null?void 0:x.length)<p?(i(),g("div",Y,[t(D,{class:"w-full",type:"primary",onClick:k},{default:l(()=>[...e[1]||(e[1]=[L("添加图片",-1)])]),_:1})])):P("",!0)]}),_:1})]),_:1})])}}});export{le as _};
import{o as I,q as i,r as g,v as t,D as l,bg as O,s,u,bQ as j,O as F,b6 as q,b7 as z,I as A,K,L,P,b9 as Q,p as R,cm as b}from"./.pnpm-Dwh6tNxD.js";import{_ as S}from"./index-39SS-XKl.js";import{c as T,i as v}from"./index-C0Q8AuuZ.js";import{_ as G}from"./picker-D3OnL1mV.js";import{_ as H}from"./picker-2bpe8Dva.js";const J={class:"bg-fill-light flex items-center w-full p-4 mt-4"},M={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"},p=5,le=I({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(r,{emit:h}){const m=h,c=r,f=R({get:()=>c.content,set:a=>{m("update:content",a)}}),k=()=>{var a;if(((a=c.content.data)==null?void 0:a.length)<p){const e=b(c.content);e.data.push({is_show:"1",image:"",name:"",link:{}}),m("update:content",e)}else v.msgError(`最多添加${p}张图片`)},w=a=>{var d;if(((d=c.content.data)==null?void 0:d.length)<=1)return v.msgError("最少保留一张图片");const e=b(c.content);e.data.splice(a,1),m("update:content",e)};return(a,e)=>{const d=H,y=z,_=q,E=G,U=A,C=T,B=S,D=K,N=O,$=Q;return i(),g("div",null,[t($,{"label-width":"70px"},{default:l(()=>[t(N,{shadow:"never",class:"!border-none flex mt-2"},{default:l(()=>{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(u(j),{class:"draggable",modelValue:u(f).data,"onUpdate:modelValue":e[0]||(e[0]=o=>u(f).data=o),animation:"300",handle:".drag-move","item-key":"index"},{item:l(({element:o,index:V})=>[(i(),F(B,{key:V,onClose:n=>w(V),class:"w-[467px]"},{default:l(()=>[s("div",J,[t(d,{modelValue:o.image,"onUpdate:modelValue":n=>o.image=n,"upload-class":"bg-body","exclude-domain":""},null,8,["modelValue","onUpdate:modelValue"]),s("div",M,[t(_,{label:"图片名称"},{default:l(()=>[t(y,{modelValue:o.name,"onUpdate:modelValue":n=>o.name=n,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(_,{class:"mt-[18px]",label:"图片链接"},{default:l(()=>[t(E,{modelValue:o.link,"onUpdate:modelValue":n=>o.link=n},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),t(_,{label:"是否显示",class:"mt-[18px]"},{default:l(()=>[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=r.content.data)==null?void 0:x.length)<p?(i(),g("div",Y,[t(D,{class:"w-full",type:"primary",onClick:k},{default:l(()=>[...e[1]||(e[1]=[L("添加图片",-1)])]),_:1})])):P("",!0)]}),_:1})]),_:1})])}}});export{le as _};
@@ -1 +1 @@
import{o as j,q as V,r as v,v as e,D as t,s,L as h,bg as q,b6 as A,u as m,bQ as K,ae as M,b7 as O,I as Q,K as R,T as w,P as G,b9 as H,F as J,p as y}from"./.pnpm-Dwh6tNxD.js";import{_ as W}from"./index-4fo3NoYp.js";import{_ as X}from"./picker-K9bQMD5v.js";import{_ as Y}from"./picker-DYD_beSt.js";import{c as Z,i as b}from"./index-C9ilrjDr.js";import{_ as ee}from"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";const le={class:"mb-[18px] max-w-[400px]"},oe={class:"bg-fill-light w-full p-4 mt-4"},te={class:"upload-btn w-[60px] h-[60px]"},se={class:"upload-btn w-[60px] h-[60px]"},ae={class:"flex-1 flex items-center"},ne={class:"drag-move cursor-move ml-auto"},de={key:0,class:"mt-4"},c=5,p=2,_e=j({__name:"attr",props:{modelValue:{type:Object,default:()=>({list:[],style:{}})}},emits:["update:modelValue"],setup(k,{emit:U}){const C=k,E=U,n=y({get(){return C.modelValue},set(a){E("update:modelValue",a)}}),$=y(()=>{var a;return((a=n.value.list)==null?void 0:a.filter(l=>l.is_show=="1"))||[]}),z=()=>{var a;((a=n.value.list)==null?void 0:a.length)<c?n.value.list.push({name:"",selected:"",unselected:"",is_show:1,link:{}}):b.msgError(`最多添加${c}`)},B=a=>{var l;if(((l=n.value.list)==null?void 0:l.length)<=p)return b.msgError(`最少保留${p}`);n.value.list.splice(a,1)},D=a=>a.relatedContext.index!=0,F=a=>{if($.value.length<p)return a.is_show=1,b.msgError(`最少显示${p}`)};return(a,l)=>{const _=q,x=ee,i=A,f=Z,g=Y,N=O,I=X,P=Q,S=W,T=R,L=H;return V(),v(J,null,[e(_,{shadow:"never",class:"!border-none flex"},{default:t(()=>[...l[3]||(l[3]=[s("div",{class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2 text-xl font-medium"},[h(" 底部导航设置 "),s("span",{class:"form-tips ml-[10px] !mt-0"}," 至少添加2个导航,最多添加5个导航 ")],-1)])]),_:1}),e(L,{"label-width":"70px"},{default:t(()=>[e(_,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>[l[4]||(l[4]=s("div",{class:"flex items-end mb-4"},[s("div",{class:"text-base text-[#101010] font-medium"},"展示样式")],-1)),e(i,{label:"默认颜色"},{default:t(()=>[e(x,{class:"max-w-[400px]",modelValue:m(n).style.default_color,"onUpdate:modelValue":l[0]||(l[0]=u=>m(n).style.default_color=u),"default-color":"#999999"},null,8,["modelValue"])]),_:1}),e(i,{label:"选中颜色",style:{"margin-bottom":"0"}},{default:t(()=>[e(x,{class:"max-w-[400px]",modelValue:m(n).style.selected_color,"onUpdate:modelValue":l[1]||(l[1]=u=>m(n).style.selected_color=u),"default-color":"#4173ff"},null,8,["modelValue"])]),_:1})]),_:1}),e(_,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>{var u;return[l[7]||(l[7]=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"},"建议图片尺寸:100px*100px")],-1)),s("div",le,[e(m(K),{class:"draggable",modelValue:m(n).list,"onUpdate:modelValue":l[2]||(l[2]=o=>m(n).list=o),animation:"300",draggable:".draggable",handle:".drag-move",move:D,"item-key":"index"},{item:t(({element:o,index:r})=>[e(S,{onClose:d=>B(r),class:M(["max-w-[400px]",{draggable:r!=0}]),"show-close":r!==0},{default:t(()=>[s("div",oe,[e(i,{label:"导航图标"},{default:t(()=>[e(g,{modelValue:o.unselected,"onUpdate:modelValue":d=>o.unselected=d,"upload-class":"bg-body","exclude-domain":"",size:"60px"},{upload:t(()=>[s("div",te,[e(f,{name:"el-icon-Plus",size:16}),l[5]||(l[5]=s("span",{class:"text-xs leading-5"}," 未选中 ",-1))])]),_:1},8,["modelValue","onUpdate:modelValue"]),e(g,{modelValue:o.selected,"onUpdate:modelValue":d=>o.selected=d,"exclude-domain":"","upload-class":"bg-body",size:"60px"},{upload:t(()=>[s("div",se,[e(f,{name:"el-icon-Plus",size:16}),l[6]||(l[6]=s("span",{class:"text-xs leading-5"}," 选中 ",-1))])]),_:1},8,["modelValue","onUpdate:modelValue"])]),_:2},1024),e(i,{label:"导航名称"},{default:t(()=>[e(N,{modelValue:o.name,"onUpdate:modelValue":d=>o.name=d,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),e(i,{label:"链接地址"},{default:t(()=>[e(I,{"is-tab":!0,disabled:r===0,modelValue:o.link,"onUpdate:modelValue":d=>o.link=d},null,8,["disabled","modelValue","onUpdate:modelValue"])]),_:2},1024),e(i,{label:"是否显示"},{default:t(()=>[s("div",ae,[e(P,{disabled:r==0,modelValue:o.is_show,"onUpdate:modelValue":d=>o.is_show=d,"active-value":1,"inactive-value":0,onChange:d=>F(o)},null,8,["disabled","modelValue","onUpdate:modelValue","onChange"]),s("div",ne,[e(f,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])]),_:2},1032,["onClose","show-close","class"])]),_:1},8,["modelValue"])]),((u=m(n).list)==null?void 0:u.length)<c?(V(),v("div",de,[e(T,{class:"w-full",type:"primary",onClick:z},{default:t(()=>{var o;return[h(" 添加导航 "+w((o=m(n).list)==null?void 0:o.length)+" / "+w(c),1)]}),_:1})])):G("",!0)]}),_:1})]),_:1})],64)}}});export{_e as _};
import{o as j,q as V,r as v,v as e,D as t,s,L as h,bg as q,b6 as A,u as m,bQ as K,ae as M,b7 as O,I as Q,K as R,T as w,P as G,b9 as H,F as J,p as y}from"./.pnpm-Dwh6tNxD.js";import{_ as W}from"./index-39SS-XKl.js";import{_ as X}from"./picker-D3OnL1mV.js";import{_ as Y}from"./picker-2bpe8Dva.js";import{c as Z,i as b}from"./index-C0Q8AuuZ.js";import{_ as ee}from"./index.vue_vue_type_script_setup_true_lang-Cq5qrGbU.js";const le={class:"mb-[18px] max-w-[400px]"},oe={class:"bg-fill-light w-full p-4 mt-4"},te={class:"upload-btn w-[60px] h-[60px]"},se={class:"upload-btn w-[60px] h-[60px]"},ae={class:"flex-1 flex items-center"},ne={class:"drag-move cursor-move ml-auto"},de={key:0,class:"mt-4"},c=5,p=2,_e=j({__name:"attr",props:{modelValue:{type:Object,default:()=>({list:[],style:{}})}},emits:["update:modelValue"],setup(k,{emit:U}){const C=k,E=U,n=y({get(){return C.modelValue},set(a){E("update:modelValue",a)}}),$=y(()=>{var a;return((a=n.value.list)==null?void 0:a.filter(l=>l.is_show=="1"))||[]}),z=()=>{var a;((a=n.value.list)==null?void 0:a.length)<c?n.value.list.push({name:"",selected:"",unselected:"",is_show:1,link:{}}):b.msgError(`最多添加${c}`)},B=a=>{var l;if(((l=n.value.list)==null?void 0:l.length)<=p)return b.msgError(`最少保留${p}`);n.value.list.splice(a,1)},D=a=>a.relatedContext.index!=0,F=a=>{if($.value.length<p)return a.is_show=1,b.msgError(`最少显示${p}`)};return(a,l)=>{const _=q,x=ee,i=A,f=Z,g=Y,N=O,I=X,P=Q,S=W,T=R,L=H;return V(),v(J,null,[e(_,{shadow:"never",class:"!border-none flex"},{default:t(()=>[...l[3]||(l[3]=[s("div",{class:"title flex items-center before:w-[3px] before:h-[14px] before:block before:bg-primary before:mr-2 text-xl font-medium"},[h(" 底部导航设置 "),s("span",{class:"form-tips ml-[10px] !mt-0"}," 至少添加2个导航,最多添加5个导航 ")],-1)])]),_:1}),e(L,{"label-width":"70px"},{default:t(()=>[e(_,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>[l[4]||(l[4]=s("div",{class:"flex items-end mb-4"},[s("div",{class:"text-base text-[#101010] font-medium"},"展示样式")],-1)),e(i,{label:"默认颜色"},{default:t(()=>[e(x,{class:"max-w-[400px]",modelValue:m(n).style.default_color,"onUpdate:modelValue":l[0]||(l[0]=u=>m(n).style.default_color=u),"default-color":"#999999"},null,8,["modelValue"])]),_:1}),e(i,{label:"选中颜色",style:{"margin-bottom":"0"}},{default:t(()=>[e(x,{class:"max-w-[400px]",modelValue:m(n).style.selected_color,"onUpdate:modelValue":l[1]||(l[1]=u=>m(n).style.selected_color=u),"default-color":"#4173ff"},null,8,["modelValue"])]),_:1})]),_:1}),e(_,{shadow:"never",class:"!border-none flex mt-2"},{default:t(()=>{var u;return[l[7]||(l[7]=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"},"建议图片尺寸:100px*100px")],-1)),s("div",le,[e(m(K),{class:"draggable",modelValue:m(n).list,"onUpdate:modelValue":l[2]||(l[2]=o=>m(n).list=o),animation:"300",draggable:".draggable",handle:".drag-move",move:D,"item-key":"index"},{item:t(({element:o,index:r})=>[e(S,{onClose:d=>B(r),class:M(["max-w-[400px]",{draggable:r!=0}]),"show-close":r!==0},{default:t(()=>[s("div",oe,[e(i,{label:"导航图标"},{default:t(()=>[e(g,{modelValue:o.unselected,"onUpdate:modelValue":d=>o.unselected=d,"upload-class":"bg-body","exclude-domain":"",size:"60px"},{upload:t(()=>[s("div",te,[e(f,{name:"el-icon-Plus",size:16}),l[5]||(l[5]=s("span",{class:"text-xs leading-5"}," 未选中 ",-1))])]),_:1},8,["modelValue","onUpdate:modelValue"]),e(g,{modelValue:o.selected,"onUpdate:modelValue":d=>o.selected=d,"exclude-domain":"","upload-class":"bg-body",size:"60px"},{upload:t(()=>[s("div",se,[e(f,{name:"el-icon-Plus",size:16}),l[6]||(l[6]=s("span",{class:"text-xs leading-5"}," 选中 ",-1))])]),_:1},8,["modelValue","onUpdate:modelValue"])]),_:2},1024),e(i,{label:"导航名称"},{default:t(()=>[e(N,{modelValue:o.name,"onUpdate:modelValue":d=>o.name=d,placeholder:"请输入名称"},null,8,["modelValue","onUpdate:modelValue"])]),_:2},1024),e(i,{label:"链接地址"},{default:t(()=>[e(I,{"is-tab":!0,disabled:r===0,modelValue:o.link,"onUpdate:modelValue":d=>o.link=d},null,8,["disabled","modelValue","onUpdate:modelValue"])]),_:2},1024),e(i,{label:"是否显示"},{default:t(()=>[s("div",ae,[e(P,{disabled:r==0,modelValue:o.is_show,"onUpdate:modelValue":d=>o.is_show=d,"active-value":1,"inactive-value":0,onChange:d=>F(o)},null,8,["disabled","modelValue","onUpdate:modelValue","onChange"]),s("div",ne,[e(f,{name:"el-icon-Rank",size:"18"})])])]),_:2},1024)])]),_:2},1032,["onClose","show-close","class"])]),_:1},8,["modelValue"])]),((u=m(n).list)==null?void 0:u.length)<c?(V(),v("div",de,[e(T,{class:"w-full",type:"primary",onClick:z},{default:t(()=>{var o;return[h(" 添加导航 "+w((o=m(n).list)==null?void 0:o.length)+" / "+w(c),1)]}),_:1})])):G("",!0)]}),_:1})]),_:1})],64)}}});export{_e as _};
@@ -1 +1 @@
import{o as V,q as E,r as w,v as t,D as o,bg as y,b6 as g,b7 as B,u as s,s as a,bc as C,bf as N,L as u,b9 as U,p as j}from"./.pnpm-Dwh6tNxD.js";import{_ as k}from"./add-nav.vue_vue_type_script_setup_true_lang-D73JnCTp.js";const D={class:"flex-1"},O=V({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(p,{emit:i}){const f=i,_=p,l=j({get:()=>_.content,set:m=>{f("update:content",m)}});return(m,e)=>{const x=B,c=g,d=y,r=N,b=C,v=U;return E(),w("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(b,{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",D,[t(k,{modelValue:s(l).data,"onUpdate:modelValue":e[2]||(e[2]=n=>s(l).data=n)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{O as _};
import{o as V,q as E,r as w,v as t,D as o,bg as y,b6 as g,b7 as B,u as s,s as a,bc as C,bf as N,L as u,b9 as U,p as j}from"./.pnpm-Dwh6tNxD.js";import{_ as k}from"./add-nav.vue_vue_type_script_setup_true_lang-CH8U6Lyn.js";const D={class:"flex-1"},O=V({__name:"attr",props:{content:{type:Object,default:()=>({})},styles:{type:Object,default:()=>({})}},emits:["update:content"],setup(p,{emit:i}){const f=i,_=p,l=j({get:()=>_.content,set:m=>{f("update:content",m)}});return(m,e)=>{const x=B,c=g,d=y,r=N,b=C,v=U;return E(),w("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(b,{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",D,[t(k,{modelValue:s(l).data,"onUpdate:modelValue":e[2]||(e[2]=n=>s(l).data=n)},null,8,["modelValue"])])]),_:1})]),_:1})])}}});export{O as _};
@@ -1 +0,0 @@
import{_ as o}from"./auth.vue_vue_type_script_setup_true_lang-DQuZW-nx.js";import"./.pnpm-Dwh6tNxD.js";import"./menu-_5V8MFoG.js";import"./index-C9ilrjDr.js";import"./role-C1NLqyir.js";import"./index-BM6NmNnG.js";export{o as default};
@@ -0,0 +1 @@
import{_ as o}from"./auth.vue_vue_type_script_setup_true_lang-CIpBYzCi.js";import"./.pnpm-Dwh6tNxD.js";import"./menu-0FOsMWO2.js";import"./index-C0Q8AuuZ.js";import"./role-BAOZKGDz.js";import"./index-CfJcNX3X.js";export{o as default};
@@ -1 +1 @@
import{o as O,q as k,r as U,v as s,D as d,ac as H,O as I,b9 as j,u as c,a2 as z,b6 as G,s as y,bd as J,C as P,bU as Q,bi as W,a8 as f,M as r,ba as X,n as b}from"./.pnpm-Dwh6tNxD.js";import{m as Y}from"./menu-_5V8MFoG.js";import{a as Z}from"./role-C1NLqyir.js";import{_ as $}from"./index-BM6NmNnG.js";import{x as ee}from"./index-C9ilrjDr.js";const te={class:"edit-popup"},re=O({__name:"auth",emits:["success","close"],setup(ae,{expose:x,emit:C}){const _=C,l=f(),h=f(),u=f(),g=r(!1),i=r(!0),m=r(!1),v=r([]),p=r([]),o=X({id:"",name:"",desc:"",sort:0,data_scope:1,menu_id:[]}),E={name:[{required:!0,message:"请输入名称",trigger:["blur"]}]},w=()=>{m.value=!0,Y().then(e=>{p.value=e,v.value=ee(e),b(()=>{A()}),m.value=!1})},R=()=>{var a,n;const e=(a=l.value)==null?void 0:a.getCheckedKeys(),t=(n=l.value)==null?void 0:n.getHalfCheckedKeys();return e==null||e.unshift.apply(e,t),e},A=()=>{o.menu_id.forEach(e=>{b(()=>{var t;(t=l.value)==null||t.setChecked(e,!0,!1)})})},D=e=>{const t=p.value;for(let a=0;a<t.length;a++)l.value.store.nodesMap[t[a].id].expanded=e},K=e=>{var t,a;e?(t=l.value)==null||t.setCheckedKeys(v.value.map(n=>n.id)):(a=l.value)==null||a.setCheckedKeys([])},V=async()=>{var e,t;await((e=h.value)==null?void 0:e.validate()),o.menu_id=R(),await Z(o),(t=u.value)==null||t.close(),_("success")},B=()=>{_("close")},S=()=>{var e;(e=u.value)==null||e.open()},T=async e=>{for(const t in o)e[t]!=null&&e[t]!=null&&(o[t]=e[t])};return w(),x({open:S,setFormData:T}),(e,t)=>{const a=J,n=Q,F=G,q=z,L=j,M=W;return k(),U("div",te,[s($,{ref_key:"popupRef",ref:u,title:"分配权限",async:!0,width:"550px",onConfirm:V,onClose:B},{default:d(()=>[H((k(),I(L,{class:"ls-form",ref_key:"formRef",ref:h,rules:E,model:c(o),"label-width":"60px"},{default:d(()=>[s(q,{class:"h-[400px] sm:h-[600px]"},{default:d(()=>[s(F,{label:"权限",prop:"menu_id"},{default:d(()=>[y("div",null,[s(a,{label:"展开/折叠",onChange:D}),s(a,{label:"全选/不全选",onChange:K}),s(a,{modelValue:c(i),"onUpdate:modelValue":t[0]||(t[0]=N=>P(i)?i.value=N:null),label:"父子联动"},null,8,["modelValue"]),y("div",null,[s(n,{ref_key:"treeRef",ref:l,data:c(p),props:{label:"name",children:"children"},"check-strictly":!c(i),"node-key":"id","default-expand-all":c(g),"show-checkbox":""},null,8,["data","check-strictly","default-expand-all"])])])]),_:1})]),_:1})]),_:1},8,["model"])),[[M,c(m)]])]),_:1},512)])}}});export{re as _};
import{o as O,q as k,r as U,v as s,D as d,ac as H,O as I,b9 as j,u as c,a2 as z,b6 as G,s as y,bd as J,C as P,bU as Q,bi as W,a8 as f,M as r,ba as X,n as b}from"./.pnpm-Dwh6tNxD.js";import{m as Y}from"./menu-0FOsMWO2.js";import{a as Z}from"./role-BAOZKGDz.js";import{_ as $}from"./index-CfJcNX3X.js";import{x as ee}from"./index-C0Q8AuuZ.js";const te={class:"edit-popup"},re=O({__name:"auth",emits:["success","close"],setup(ae,{expose:x,emit:C}){const _=C,l=f(),h=f(),u=f(),g=r(!1),i=r(!0),m=r(!1),v=r([]),p=r([]),o=X({id:"",name:"",desc:"",sort:0,data_scope:1,menu_id:[]}),E={name:[{required:!0,message:"请输入名称",trigger:["blur"]}]},w=()=>{m.value=!0,Y().then(e=>{p.value=e,v.value=ee(e),b(()=>{A()}),m.value=!1})},R=()=>{var a,n;const e=(a=l.value)==null?void 0:a.getCheckedKeys(),t=(n=l.value)==null?void 0:n.getHalfCheckedKeys();return e==null||e.unshift.apply(e,t),e},A=()=>{o.menu_id.forEach(e=>{b(()=>{var t;(t=l.value)==null||t.setChecked(e,!0,!1)})})},D=e=>{const t=p.value;for(let a=0;a<t.length;a++)l.value.store.nodesMap[t[a].id].expanded=e},K=e=>{var t,a;e?(t=l.value)==null||t.setCheckedKeys(v.value.map(n=>n.id)):(a=l.value)==null||a.setCheckedKeys([])},V=async()=>{var e,t;await((e=h.value)==null?void 0:e.validate()),o.menu_id=R(),await Z(o),(t=u.value)==null||t.close(),_("success")},B=()=>{_("close")},S=()=>{var e;(e=u.value)==null||e.open()},T=async e=>{for(const t in o)e[t]!=null&&e[t]!=null&&(o[t]=e[t])};return w(),x({open:S,setFormData:T}),(e,t)=>{const a=J,n=Q,F=G,q=z,L=j,M=W;return k(),U("div",te,[s($,{ref_key:"popupRef",ref:u,title:"分配权限",async:!0,width:"550px",onConfirm:V,onClose:B},{default:d(()=>[H((k(),I(L,{class:"ls-form",ref_key:"formRef",ref:h,rules:E,model:c(o),"label-width":"60px"},{default:d(()=>[s(q,{class:"h-[400px] sm:h-[600px]"},{default:d(()=>[s(F,{label:"权限",prop:"menu_id"},{default:d(()=>[y("div",null,[s(a,{label:"展开/折叠",onChange:D}),s(a,{label:"全选/不全选",onChange:K}),s(a,{modelValue:c(i),"onUpdate:modelValue":t[0]||(t[0]=N=>P(i)?i.value=N:null),label:"父子联动"},null,8,["modelValue"]),y("div",null,[s(n,{ref_key:"treeRef",ref:l,data:c(p),props:{label:"name",children:"children"},"check-strictly":!c(i),"node-key":"id","default-expand-all":c(g),"show-checkbox":""},null,8,["data","check-strictly","default-expand-all"])])])]),_:1})]),_:1})]),_:1},8,["model"])),[[M,c(m)]])]),_:1},512)])}}});export{re as _};
@@ -1 +1 @@
import{o as y,q as m,r as h,v as e,D as l,bh as K,b9 as P,u as a,b6 as N,b7 as O,b8 as j,bm as q,bn as z,F as I,G as R,O as w,K as S,L as _,bg as $,ac as A,bj as G,bk as H,s as p,T as v,ae as J,bi as M,C as Q,ba as W}from"./.pnpm-Dwh6tNxD.js";import{_ as X}from"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import{h as Y}from"./index-C9ilrjDr.js";import{_ as Z}from"./index.vue_vue_type_script_setup_true_lang-C9hPqHM6.js";import{g as ee,h as te}from"./finance-CnBidH5A.js";import{u as ae}from"./useDictOptions-VG1Pcf0t.js";import{u as ne}from"./usePaging-DOuAwzL9.js";const le={class:"flex items-center"},oe={class:"flex justify-end mt-4"},se=y({name:"balanceDetail"}),be=y({...se,setup(ie){const o=W({user_info:"",change_type:"",start_time:"",end_time:""}),{pager:i,getLists:d,resetPage:c,resetParams:C}=ne({fetchFun:ee,params:o}),{optionsData:x}=ae({change_type:{api:te}});return d(),(re,n)=>{const V=K,E=O,r=N,u=z,T=q,k=Z,f=S,D=P,b=$,s=H,U=Y,B=G,F=X,L=M;return m(),h("div",null,[e(b,{class:"!border-none",shadow:"never"},{default:l(()=>[e(V,{type:"warning",title:"温馨提示:用户账户变动记录",closable:!1,"show-icon":""}),e(D,{ref:"formRef",class:"mb-[-16px] mt-[16px]",model:a(o),inline:!0},{default:l(()=>[e(r,{class:"w-[280px]",label:"用户信息"},{default:l(()=>[e(E,{modelValue:a(o).user_info,"onUpdate:modelValue":n[0]||(n[0]=t=>a(o).user_info=t),placeholder:"请输入用户账号/昵称/手机号",clearable:"",onKeyup:j(a(c),["enter"])},null,8,["modelValue","onKeyup"])]),_:1}),e(r,{class:"w-[280px]",label:"变动类型"},{default:l(()=>[e(T,{modelValue:a(o).change_type,"onUpdate:modelValue":n[1]||(n[1]=t=>a(o).change_type=t)},{default:l(()=>[e(u,{label:"全部",value:""}),(m(!0),h(I,null,R(a(x).change_type,(t,g)=>(m(),w(u,{key:g,label:t,value:g},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),_:1}),e(r,{label:"记录时间"},{default:l(()=>[e(k,{startTime:a(o).start_time,"onUpdate:startTime":n[2]||(n[2]=t=>a(o).start_time=t),endTime:a(o).end_time,"onUpdate:endTime":n[3]||(n[3]=t=>a(o).end_time=t)},null,8,["startTime","endTime"])]),_:1}),e(r,null,{default:l(()=>[e(f,{type:"primary",onClick:a(c)},{default:l(()=>[...n[5]||(n[5]=[_("查询",-1)])]),_:1},8,["onClick"]),e(f,{onClick:a(C)},{default:l(()=>[...n[6]||(n[6]=[_("重置",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["model"])]),_:1}),e(b,{class:"!border-none mt-4",shadow:"never"},{default:l(()=>[A((m(),w(B,{size:"large",data:a(i).lists},{default:l(()=>[e(s,{label:"用户账号",prop:"account","min-width":"100"}),e(s,{label:"用户昵称","min-width":"160"},{default:l(({row:t})=>[p("div",le,[e(U,{class:"flex-none mr-2",src:t.avatar,width:40,height:40,"preview-teleported":"",fit:"contain"},null,8,["src"]),_(" "+v(t.nickname),1)])]),_:1}),e(s,{label:"手机号码",prop:"mobile","min-width":"100"}),e(s,{label:"变动金额",prop:"change_amount","min-width":"100"},{default:l(({row:t})=>[p("span",{class:J({"text-error":t.action==2})},v(t.change_amount),3)]),_:1}),e(s,{label:"剩余金额",prop:"left_amount","min-width":"100"}),e(s,{label:"变动类型",prop:"change_type_desc","min-width":"120"}),e(s,{label:"来源单号",prop:"source_sn","min-width":"100"}),e(s,{label:"记录时间",prop:"create_time","min-width":"120"})]),_:1},8,["data"])),[[L,a(i).loading]]),p("div",oe,[e(F,{modelValue:a(i),"onUpdate:modelValue":n[4]||(n[4]=t=>Q(i)?i.value=t:null),onChange:a(d)},null,8,["modelValue","onChange"])])]),_:1})])}}});export{be as default};
import{o as y,q as m,r as h,v as e,D as l,bh as K,b9 as P,u as a,b6 as N,b7 as O,b8 as j,bm as q,bn as z,F as I,G as R,O as w,K as S,L as _,bg as $,ac as A,bj as G,bk as H,s as p,T as v,ae as J,bi as M,C as Q,ba as W}from"./.pnpm-Dwh6tNxD.js";import{_ as X}from"./index.vue_vue_type_script_setup_true_lang-D0KAQf1t.js";import{h as Y}from"./index-C0Q8AuuZ.js";import{_ as Z}from"./index.vue_vue_type_script_setup_true_lang-C9hPqHM6.js";import{g as ee,h as te}from"./finance-BoalIhuu.js";import{u as ae}from"./useDictOptions-C-sTmCFl.js";import{u as ne}from"./usePaging-DOuAwzL9.js";const le={class:"flex items-center"},oe={class:"flex justify-end mt-4"},se=y({name:"balanceDetail"}),be=y({...se,setup(ie){const o=W({user_info:"",change_type:"",start_time:"",end_time:""}),{pager:i,getLists:d,resetPage:c,resetParams:C}=ne({fetchFun:ee,params:o}),{optionsData:x}=ae({change_type:{api:te}});return d(),(re,n)=>{const V=K,E=O,r=N,u=z,T=q,k=Z,f=S,D=P,b=$,s=H,U=Y,B=G,F=X,L=M;return m(),h("div",null,[e(b,{class:"!border-none",shadow:"never"},{default:l(()=>[e(V,{type:"warning",title:"温馨提示:用户账户变动记录",closable:!1,"show-icon":""}),e(D,{ref:"formRef",class:"mb-[-16px] mt-[16px]",model:a(o),inline:!0},{default:l(()=>[e(r,{class:"w-[280px]",label:"用户信息"},{default:l(()=>[e(E,{modelValue:a(o).user_info,"onUpdate:modelValue":n[0]||(n[0]=t=>a(o).user_info=t),placeholder:"请输入用户账号/昵称/手机号",clearable:"",onKeyup:j(a(c),["enter"])},null,8,["modelValue","onKeyup"])]),_:1}),e(r,{class:"w-[280px]",label:"变动类型"},{default:l(()=>[e(T,{modelValue:a(o).change_type,"onUpdate:modelValue":n[1]||(n[1]=t=>a(o).change_type=t)},{default:l(()=>[e(u,{label:"全部",value:""}),(m(!0),h(I,null,R(a(x).change_type,(t,g)=>(m(),w(u,{key:g,label:t,value:g},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),_:1}),e(r,{label:"记录时间"},{default:l(()=>[e(k,{startTime:a(o).start_time,"onUpdate:startTime":n[2]||(n[2]=t=>a(o).start_time=t),endTime:a(o).end_time,"onUpdate:endTime":n[3]||(n[3]=t=>a(o).end_time=t)},null,8,["startTime","endTime"])]),_:1}),e(r,null,{default:l(()=>[e(f,{type:"primary",onClick:a(c)},{default:l(()=>[...n[5]||(n[5]=[_("查询",-1)])]),_:1},8,["onClick"]),e(f,{onClick:a(C)},{default:l(()=>[...n[6]||(n[6]=[_("重置",-1)])]),_:1},8,["onClick"])]),_:1})]),_:1},8,["model"])]),_:1}),e(b,{class:"!border-none mt-4",shadow:"never"},{default:l(()=>[A((m(),w(B,{size:"large",data:a(i).lists},{default:l(()=>[e(s,{label:"用户账号",prop:"account","min-width":"100"}),e(s,{label:"用户昵称","min-width":"160"},{default:l(({row:t})=>[p("div",le,[e(U,{class:"flex-none mr-2",src:t.avatar,width:40,height:40,"preview-teleported":"",fit:"contain"},null,8,["src"]),_(" "+v(t.nickname),1)])]),_:1}),e(s,{label:"手机号码",prop:"mobile","min-width":"100"}),e(s,{label:"变动金额",prop:"change_amount","min-width":"100"},{default:l(({row:t})=>[p("span",{class:J({"text-error":t.action==2})},v(t.change_amount),3)]),_:1}),e(s,{label:"剩余金额",prop:"left_amount","min-width":"100"}),e(s,{label:"变动类型",prop:"change_type_desc","min-width":"120"}),e(s,{label:"来源单号",prop:"source_sn","min-width":"100"}),e(s,{label:"记录时间",prop:"create_time","min-width":"120"})]),_:1},8,["data"])),[[L,a(i).loading]]),p("div",oe,[e(F,{modelValue:a(i),"onUpdate:modelValue":n[4]||(n[4]=t=>Q(i)?i.value=t:null),onChange:a(d)},null,8,["modelValue","onChange"])])]),_:1})])}}});export{be as default};
@@ -1 +1 @@
import{o as T,W as $,ap as j,E as p,aq as z,q as d,r as l,s as r,v as c,D as y,u as S,b5 as I,w as A,F as D,L as M,K as F,M as k,n as C}from"./.pnpm-Dwh6tNxD.js";import{_ as K}from"./footer.vue_vue_type_script_setup_true_lang-BbowIPV2.js";import{u as Q,g as V,P as L,a as X,b as G,_ as H}from"./index-C9ilrjDr.js";import{a as J}from"./wecomOauthPostMessage-C_e6VGrO.js";const Y={class:"bind-wx flex flex-col"},Z={class:"flex-1 flex items-center justify-center"},ee={class:"bind-wx-card bg-body rounded-md px-10 py-10 w-[480px]"},te={key:0,class:"text-center py-10"},oe={key:0,class:"text-center py-10"},ne={key:1,id:"wxwork_bind_qrcode_container",class:"wxwork-qrcode mx-auto"},ae={class:"mt-8 flex justify-center gap-4"},w="bind_wxwork",g="like_admin_wx_bind_oauth",se=T({__name:"bind-work-wechat",setup(re){const u=$(),f=Q(),x=k(!1),_=k(!1),m=k({corp_id:"",agent_id:""}),U=()=>/wxwork/i.test(navigator.userAgent),v=()=>window.location.origin+window.location.pathname+"?bind_wxwork=1";function W(){const o=new URLSearchParams(window.location.search),e=window.location.hash||"",t=e.includes("?")?e.split("?").slice(1).join("?"):"";return t&&new URLSearchParams(t).forEach((n,i)=>{o.has(i)||o.set(i,n)}),o}const E=()=>{f.logout()},q=async()=>{try{await f.getUserInfo()}catch{}if(f.isPaw===0){u.replace("/change-password");return}u.replace(L.INDEX)},b=async o=>{_.value=!0;try{await G({code:o}),window.history.replaceState({},"",window.location.pathname),await q()}catch(e){console.error(e),p.error((e==null?void 0:e.msg)||(e==null?void 0:e.message)||"绑定失败"),_.value=!1}};let s=null;const B=async()=>{if(!m.value.corp_id)return;x.value=!0,window.WwLogin||await new Promise((e,t)=>{const n=document.createElement("script");n.src="https://wwcdn.weixin.qq.com/node/wework/wwopen/js/wwLogin-1.2.7.js",n.onload=()=>e(),n.onerror=()=>t(new Error("加载企业微信 JS 失败")),document.head.appendChild(n)}),await C(),x.value=!1,await C();const o=encodeURIComponent(v());new window.WwLogin({id:"wxwork_bind_qrcode_container",appid:m.value.corp_id,agentid:m.value.agent_id,redirect_uri:o,lang:"zh",state:w,href:"",self_redirect:!1})};return j(async()=>{let o="";try{o=(new URLSearchParams(window.location.search).get("code")||"").trim()}catch{o=""}if(!V()){p.error("请先登录"),u.push(L.LOGIN);return}const e=W(),t=o||(e.get("code")||"").trim(),n=e.get("state"),i=n!=null?String(n).trim():"",P=i===w||i==="admin_bind_wx"||i.toLowerCase()===w.toLowerCase(),R=e.get("bind_wxwork")==="1",N=!!t&&i===""&&u.currentRoute.value.path==="/bind-work-wechat";if(t&&(P||R||N)){if(sessionStorage.getItem(g)===t)return;sessionStorage.setItem(g,t);try{await b(t)}finally{sessionStorage.removeItem(g)}return}try{const a=await X();if(!(a!=null&&a.enabled)||!a.corp_id){p.error("企业微信未配置,请联系管理员");return}if(m.value={corp_id:a.corp_id,agent_id:a.agent_id},U()){_.value=!0;const h=encodeURIComponent(v()),O=`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${a.corp_id}&redirect_uri=${h}&response_type=code&scope=snsapi_privateinfo&agentid=${a.agent_id}&state=${w}#wechat_redirect`;window.location.href=O;return}s==null||s(),s=J({pathIncludes:"bind-work-wechat",lockKey:g,wxBindState:w,onCode:h=>b(h)}),await B()}catch(a){console.error(a),p.error("获取企业微信配置失败")}}),z(()=>{s==null||s(),s=null}),(o,e)=>{const t=A,n=F;return d(),l("div",Y,[r("div",Z,[r("div",ee,[e[4]||(e[4]=r("div",{class:"text-center text-2xl font-medium mb-2"},"绑定企业微信",-1)),e[5]||(e[5]=r("div",{class:"text-center text-gray-500 text-sm mb-8"}," 根据安全策略,需绑定企业微信账号后方可使用管理后台 ",-1)),_.value?(d(),l("div",te,[c(t,{class:"is-loading mb-4",size:40,color:"var(--el-color-primary)"},{default:y(()=>[c(S(I))]),_:1}),e[0]||(e[0]=r("div",{class:"text-gray-500"},"企业微信授权中...",-1))])):(d(),l(D,{key:1},[x.value?(d(),l("div",oe,[c(t,{class:"is-loading",size:32,color:"var(--el-color-primary)"},{default:y(()=>[c(S(I))]),_:1}),e[1]||(e[1]=r("div",{class:"mt-2 text-gray-400 text-sm"},"加载扫码...",-1))])):(d(),l("div",ne)),e[2]||(e[2]=r("div",{class:"text-center text-sm text-gray-400 mt-4"}," 请使用企业微信扫描二维码完成绑定 ",-1))],64)),r("div",ae,[c(n,{onClick:E},{default:y(()=>[...e[3]||(e[3]=[M("退出登录",-1)])]),_:1})])])]),c(K)])}}}),ue=H(se,[["__scopeId","data-v-d4a61522"]]);export{ue as default};
import{o as T,W as $,ap as j,E as p,aq as z,q as d,r as l,s as r,v as c,D as y,u as S,b5 as I,w as A,F as D,L as M,K as F,M as k,n as C}from"./.pnpm-Dwh6tNxD.js";import{_ as K}from"./footer.vue_vue_type_script_setup_true_lang-DlOTnYIa.js";import{u as Q,g as V,P as L,a as X,b as G,_ as H}from"./index-C0Q8AuuZ.js";import{a as J}from"./wecomOauthPostMessage-C_e6VGrO.js";const Y={class:"bind-wx flex flex-col"},Z={class:"flex-1 flex items-center justify-center"},ee={class:"bind-wx-card bg-body rounded-md px-10 py-10 w-[480px]"},te={key:0,class:"text-center py-10"},oe={key:0,class:"text-center py-10"},ne={key:1,id:"wxwork_bind_qrcode_container",class:"wxwork-qrcode mx-auto"},ae={class:"mt-8 flex justify-center gap-4"},w="bind_wxwork",g="like_admin_wx_bind_oauth",se=T({__name:"bind-work-wechat",setup(re){const u=$(),f=Q(),x=k(!1),_=k(!1),m=k({corp_id:"",agent_id:""}),U=()=>/wxwork/i.test(navigator.userAgent),v=()=>window.location.origin+window.location.pathname+"?bind_wxwork=1";function W(){const o=new URLSearchParams(window.location.search),e=window.location.hash||"",t=e.includes("?")?e.split("?").slice(1).join("?"):"";return t&&new URLSearchParams(t).forEach((n,i)=>{o.has(i)||o.set(i,n)}),o}const E=()=>{f.logout()},q=async()=>{try{await f.getUserInfo()}catch{}if(f.isPaw===0){u.replace("/change-password");return}u.replace(L.INDEX)},b=async o=>{_.value=!0;try{await G({code:o}),window.history.replaceState({},"",window.location.pathname),await q()}catch(e){console.error(e),p.error((e==null?void 0:e.msg)||(e==null?void 0:e.message)||"绑定失败"),_.value=!1}};let s=null;const B=async()=>{if(!m.value.corp_id)return;x.value=!0,window.WwLogin||await new Promise((e,t)=>{const n=document.createElement("script");n.src="https://wwcdn.weixin.qq.com/node/wework/wwopen/js/wwLogin-1.2.7.js",n.onload=()=>e(),n.onerror=()=>t(new Error("加载企业微信 JS 失败")),document.head.appendChild(n)}),await C(),x.value=!1,await C();const o=encodeURIComponent(v());new window.WwLogin({id:"wxwork_bind_qrcode_container",appid:m.value.corp_id,agentid:m.value.agent_id,redirect_uri:o,lang:"zh",state:w,href:"",self_redirect:!1})};return j(async()=>{let o="";try{o=(new URLSearchParams(window.location.search).get("code")||"").trim()}catch{o=""}if(!V()){p.error("请先登录"),u.push(L.LOGIN);return}const e=W(),t=o||(e.get("code")||"").trim(),n=e.get("state"),i=n!=null?String(n).trim():"",P=i===w||i==="admin_bind_wx"||i.toLowerCase()===w.toLowerCase(),R=e.get("bind_wxwork")==="1",N=!!t&&i===""&&u.currentRoute.value.path==="/bind-work-wechat";if(t&&(P||R||N)){if(sessionStorage.getItem(g)===t)return;sessionStorage.setItem(g,t);try{await b(t)}finally{sessionStorage.removeItem(g)}return}try{const a=await X();if(!(a!=null&&a.enabled)||!a.corp_id){p.error("企业微信未配置,请联系管理员");return}if(m.value={corp_id:a.corp_id,agent_id:a.agent_id},U()){_.value=!0;const h=encodeURIComponent(v()),O=`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${a.corp_id}&redirect_uri=${h}&response_type=code&scope=snsapi_privateinfo&agentid=${a.agent_id}&state=${w}#wechat_redirect`;window.location.href=O;return}s==null||s(),s=J({pathIncludes:"bind-work-wechat",lockKey:g,wxBindState:w,onCode:h=>b(h)}),await B()}catch(a){console.error(a),p.error("获取企业微信配置失败")}}),z(()=>{s==null||s(),s=null}),(o,e)=>{const t=A,n=F;return d(),l("div",Y,[r("div",Z,[r("div",ee,[e[4]||(e[4]=r("div",{class:"text-center text-2xl font-medium mb-2"},"绑定企业微信",-1)),e[5]||(e[5]=r("div",{class:"text-center text-gray-500 text-sm mb-8"}," 根据安全策略,需绑定企业微信账号后方可使用管理后台 ",-1)),_.value?(d(),l("div",te,[c(t,{class:"is-loading mb-4",size:40,color:"var(--el-color-primary)"},{default:y(()=>[c(S(I))]),_:1}),e[0]||(e[0]=r("div",{class:"text-gray-500"},"企业微信授权中...",-1))])):(d(),l(D,{key:1},[x.value?(d(),l("div",oe,[c(t,{class:"is-loading",size:32,color:"var(--el-color-primary)"},{default:y(()=>[c(S(I))]),_:1}),e[1]||(e[1]=r("div",{class:"mt-2 text-gray-400 text-sm"},"加载扫码...",-1))])):(d(),l("div",ne)),e[2]||(e[2]=r("div",{class:"text-center text-sm text-gray-400 mt-4"}," 请使用企业微信扫描二维码完成绑定 ",-1))],64)),r("div",ae,[c(n,{onClick:E},{default:y(()=>[...e[3]||(e[3]=[M("退出登录",-1)])]),_:1})])])]),c(K)])}}}),ue=H(se,[["__scopeId","data-v-d4a61522"]]);export{ue as default};

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