更新
This commit is contained in:
@@ -351,19 +351,35 @@
|
||||
<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
|
||||
<el-tree-select
|
||||
v-model="poolForm.member_admin_ids"
|
||||
:data="memberDepartmentTree"
|
||||
:props="memberTreeProps"
|
||||
:default-expanded-keys="memberTreeDefaultExpandedKeys"
|
||||
:filter-node-method="filterMemberTreeNode"
|
||||
:disabled="savingPool"
|
||||
node-key="value"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
show-checkbox
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="选择后由企业微信生成一个多人分流链接"
|
||||
:max-collapse-tags="2"
|
||||
:multiple-limit="500"
|
||||
:render-after-expand="false"
|
||||
placeholder="按部门展开,或搜索姓名 / 部门 / 企微 userid"
|
||||
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>
|
||||
<template #default="{ data }">
|
||||
<span class="member-tree-option" :class="`is-${data.kind}`">
|
||||
<span class="member-tree-option__label">{{ data.label }}</span>
|
||||
<span v-if="data.kind === 'department'" class="member-tree-option__count">{{ data.member_count }} 人</span>
|
||||
<span v-else class="member-tree-option__detail">{{ data.detail }}</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree-select>
|
||||
<span class="form-tip">已选 {{ poolForm.member_admin_ids.length }} 名;保存后会为每名医助生成一条成员规则,官方链接地址始终只有一个。</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="需要验证" />
|
||||
@@ -421,13 +437,44 @@ import type { WecomPromotionCustomerChatStatus } from '@/api/first_visit'
|
||||
|
||||
import WecomFloatingWidgetBuilder from './components/WecomFloatingWidgetBuilder.vue'
|
||||
|
||||
type TabName = 'links' | 'customer-stats' | 'configuration' | 'install'
|
||||
const emptyOverview = () => ({
|
||||
meta: { scope_label: '', generated_at: '' },
|
||||
config: { mode: 'internal', configured: false, ready: false, missing: [] as string[], corp_id_masked: '', agent_id: '', secret_configured: false, callback_ready: false, callback_url: '', official_doc: '' },
|
||||
summary: { configured_apps: 0, pool_count: 0, online_links: 0, today_clicks: 0 },
|
||||
pools: [] as any[], links: [] as any[], member_options: [] as any[], customer_acquisition_link_example: 'https://work.weixin.qq.com/ca/xxxxxxxx'
|
||||
})
|
||||
type TabName = 'links' | 'customer-stats' | 'configuration' | 'install'
|
||||
|
||||
interface PromotionDepartmentOption {
|
||||
id: number | string
|
||||
name: string
|
||||
children?: PromotionDepartmentOption[]
|
||||
}
|
||||
|
||||
interface PromotionMemberOption {
|
||||
id: number
|
||||
name: string
|
||||
userid: string
|
||||
display_dept_id?: number
|
||||
dept_ids: number[]
|
||||
dept_names: string[]
|
||||
}
|
||||
|
||||
interface PromotionMemberTreeNode {
|
||||
value: number | string
|
||||
label: string
|
||||
kind: 'department' | 'member'
|
||||
disabled?: boolean
|
||||
member_count?: number
|
||||
detail?: string
|
||||
search_text: string
|
||||
children?: PromotionMemberTreeNode[]
|
||||
}
|
||||
|
||||
const emptyOverview = () => ({
|
||||
meta: { scope_label: '', generated_at: '' },
|
||||
config: { mode: 'internal', configured: false, ready: false, missing: [] as string[], corp_id_masked: '', agent_id: '', secret_configured: false, callback_ready: false, callback_url: '', official_doc: '' },
|
||||
summary: { configured_apps: 0, pool_count: 0, online_links: 0, today_clicks: 0 },
|
||||
pools: [] as any[],
|
||||
links: [] as any[],
|
||||
member_options: [] as PromotionMemberOption[],
|
||||
department_options: [] as PromotionDepartmentOption[],
|
||||
customer_acquisition_link_example: 'https://work.weixin.qq.com/ca/xxxxxxxx'
|
||||
})
|
||||
|
||||
const overview = reactive(emptyOverview())
|
||||
const loading = ref(false)
|
||||
@@ -462,8 +509,11 @@ const customerStats = reactive({
|
||||
|
||||
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
|
||||
const selectedInstallPool = computed(() => overview.pools.find((item: any) => Number(item.id) === selectedInstallPoolId.value))
|
||||
const memberTreeProps = { value: 'value', label: 'label', children: 'children', disabled: 'disabled' }
|
||||
const memberDepartmentTree = computed(() => buildMemberDepartmentTree(overview.department_options, overview.member_options))
|
||||
const memberTreeDefaultExpandedKeys = computed(() => memberDepartmentTree.value.map((node) => node.value))
|
||||
const customerLinkOptions = computed(() => customerStats.link_options.length
|
||||
? customerStats.link_options
|
||||
: overview.links
|
||||
.filter((item: any) => item.id)
|
||||
@@ -739,16 +789,122 @@ function eligibility(row: any) {
|
||||
return { label: '可参与分流', className: 'is-ok' }
|
||||
}
|
||||
|
||||
function todayCount(row: any) {
|
||||
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) {
|
||||
const departments = Array.isArray(member.dept_names) && member.dept_names.length
|
||||
? member.dept_names.join(' / ')
|
||||
: '未分部门'
|
||||
return `${member.name} · ${departments} · ${member.userid}`
|
||||
}
|
||||
|
||||
function buildMemberDepartmentTree(
|
||||
departmentOptions: PromotionDepartmentOption[],
|
||||
memberOptions: PromotionMemberOption[]
|
||||
): PromotionMemberTreeNode[] {
|
||||
const availableDeptIds = new Set<number>()
|
||||
const collectDeptIds = (departments: PromotionDepartmentOption[]) => {
|
||||
departments.forEach((department) => {
|
||||
const departmentId = Number(department.id)
|
||||
if (departmentId > 0) availableDeptIds.add(departmentId)
|
||||
if (Array.isArray(department.children)) collectDeptIds(department.children)
|
||||
})
|
||||
}
|
||||
collectDeptIds(Array.isArray(departmentOptions) ? departmentOptions : [])
|
||||
|
||||
const members: PromotionMemberOption[] = []
|
||||
const seenMemberIds = new Set<number>()
|
||||
for (const rawMember of Array.isArray(memberOptions) ? memberOptions : []) {
|
||||
const memberId = Number(rawMember.id)
|
||||
if (memberId <= 0 || seenMemberIds.has(memberId)) continue
|
||||
seenMemberIds.add(memberId)
|
||||
members.push({
|
||||
id: memberId,
|
||||
name: String(rawMember.name || rawMember.userid || `成员 ${memberId}`),
|
||||
userid: String(rawMember.userid || ''),
|
||||
display_dept_id: Number(rawMember.display_dept_id || 0),
|
||||
dept_ids: Array.isArray(rawMember.dept_ids)
|
||||
? Array.from(new Set(rawMember.dept_ids.map(Number).filter((id) => id > 0)))
|
||||
: [],
|
||||
dept_names: Array.isArray(rawMember.dept_names)
|
||||
? rawMember.dept_names.map(String).filter(Boolean)
|
||||
: []
|
||||
})
|
||||
}
|
||||
|
||||
const membersByDept = new Map<number, PromotionMemberOption[]>()
|
||||
members.forEach((member) => {
|
||||
const explicitDeptId = Number(member.display_dept_id || 0)
|
||||
const displayDeptId = availableDeptIds.has(explicitDeptId)
|
||||
? explicitDeptId
|
||||
: (member.dept_ids.find((id) => availableDeptIds.has(id)) || 0)
|
||||
if (!membersByDept.has(displayDeptId)) membersByDept.set(displayDeptId, [])
|
||||
membersByDept.get(displayDeptId)?.push(member)
|
||||
})
|
||||
|
||||
const placedMemberIds = new Set<number>()
|
||||
const toMemberNode = (member: PromotionMemberOption): PromotionMemberTreeNode => {
|
||||
const departments = member.dept_names.length ? member.dept_names.join(' / ') : '未分部门'
|
||||
const detail = member.userid ? `${departments} · ${member.userid}` : departments
|
||||
return {
|
||||
value: member.id,
|
||||
label: member.name,
|
||||
kind: 'member',
|
||||
detail,
|
||||
search_text: `${member.name} ${member.userid} ${member.dept_names.join(' ')}`.toLocaleLowerCase()
|
||||
}
|
||||
}
|
||||
const byMemberName = (left: PromotionMemberOption, right: PromotionMemberOption) => left.name.localeCompare(right.name, 'zh-CN')
|
||||
|
||||
const buildDepartments = (departments: PromotionDepartmentOption[], parentPath: string[]): PromotionMemberTreeNode[] => {
|
||||
const result: PromotionMemberTreeNode[] = []
|
||||
for (const department of Array.isArray(departments) ? departments : []) {
|
||||
const departmentId = Number(department.id)
|
||||
if (departmentId <= 0) continue
|
||||
const departmentName = String(department.name || `部门 ${departmentId}`)
|
||||
const path = [...parentPath, departmentName]
|
||||
const departmentChildren = buildDepartments(
|
||||
Array.isArray(department.children) ? department.children : [],
|
||||
path
|
||||
)
|
||||
const directMembers = [...(membersByDept.get(departmentId) || [])].sort(byMemberName)
|
||||
directMembers.forEach((member) => placedMemberIds.add(member.id))
|
||||
const memberChildren = directMembers.map(toMemberNode)
|
||||
const children = [...departmentChildren, ...memberChildren]
|
||||
if (!children.length) continue
|
||||
const memberCount = children.reduce(
|
||||
(count, child) => count + (child.kind === 'member' ? 1 : Number(child.member_count || 0)),
|
||||
0
|
||||
)
|
||||
result.push({
|
||||
value: `dept:${departmentId}`,
|
||||
label: departmentName,
|
||||
kind: 'department',
|
||||
disabled: true,
|
||||
member_count: memberCount,
|
||||
search_text: `${path.join(' ')} ${children.map((child) => child.search_text).join(' ')}`.toLocaleLowerCase(),
|
||||
children
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const tree = buildDepartments(Array.isArray(departmentOptions) ? departmentOptions : [], [])
|
||||
const unassigned = members.filter((member) => !placedMemberIds.has(member.id)).sort(byMemberName)
|
||||
if (unassigned.length) {
|
||||
const children = unassigned.map(toMemberNode)
|
||||
tree.push({
|
||||
value: 'dept:unassigned',
|
||||
label: '未分部门',
|
||||
kind: 'department',
|
||||
disabled: true,
|
||||
member_count: children.length,
|
||||
search_text: `未分部门 ${children.map((child) => child.search_text).join(' ')}`.toLocaleLowerCase(),
|
||||
children
|
||||
})
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
function filterMemberTreeNode(keyword: string, data: any) {
|
||||
const query = String(keyword || '').trim().toLocaleLowerCase()
|
||||
return query === '' || data.search_text.includes(query)
|
||||
}
|
||||
|
||||
function memberSummary(pool: any) {
|
||||
@@ -946,8 +1102,13 @@ h1, h2, h3, p { margin: 0; }
|
||||
.configuration-state { display: flex; align-items: center; gap: 12px; }.configuration-state > span { display: grid; width: 36px; height: 36px; place-items: center; border-radius: 9px; color: #fff; background: var(--teal); font-size: 18px; }.is-pending .configuration-state > span { background: #e69a43; }.configuration-state strong { font-size: 14px; }.configuration-state p { margin-top: 4px; color: #718094; font-size: 11px; }
|
||||
.missing-fields { margin-top: 12px; color: #9c651f; font-size: 11px; }.missing-fields code { margin-left: 6px; padding: 3px 6px; border-radius: 4px; background: rgba(224,153,63,.11); }
|
||||
.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; }
|
||||
.configuration-actions { display: flex; align-items: center; gap: 14px; margin-top: 16px; }
|
||||
.install-pool-select { width: 220px; }
|
||||
.member-tree-option { display: inline-flex; min-width: 0; flex: 1; align-items: center; gap: 10px; }
|
||||
.member-tree-option__label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.member-tree-option.is-department .member-tree-option__label { color: #344054; font-weight: 600; }
|
||||
.member-tree-option__count { flex: 0 0 auto; color: #98a2b3; font-size: 11px; }
|
||||
.member-tree-option__detail { overflow: hidden; color: #8b97a6; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.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, .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; } }
|
||||
|
||||
@@ -1775,9 +1775,31 @@ const appointmentCellClasses = (row: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
/** 仅已预约(1)可进视频/小程序码 */
|
||||
const isAppointmentActiveForVideo = (row: any) =>
|
||||
row.has_appointment && Number(row.appointment_status) === 1
|
||||
/**
|
||||
* 找到当前可用的已预约挂号。
|
||||
* 同一诊单当天可能先完成一条挂号、随后又新增一条预约,此时行级 appointment_* 仍可能指向旧记录。
|
||||
*/
|
||||
const activeAppointment = (row: any) =>
|
||||
appointmentRows(row).find((apt: any) => Number(apt?.status) === 1) ?? null
|
||||
|
||||
/** 二维码必须使用已预约挂号对应的医生和时间,不能继续沿用行级旧挂号字段。 */
|
||||
const activeAppointmentRow = (row: any) => {
|
||||
const apt = activeAppointment(row)
|
||||
if (!apt) return null
|
||||
|
||||
return {
|
||||
...row,
|
||||
has_appointment: 1,
|
||||
appointment_id: apt.id,
|
||||
appointment_status: apt.status,
|
||||
appointment_doctor_id: apt.doctor_id,
|
||||
appointment_doctor_name: apt.doctor_name,
|
||||
appointment_time_text: apt.time_text
|
||||
}
|
||||
}
|
||||
|
||||
/** 任一挂号记录处于已预约(1)即可进视频/小程序码。 */
|
||||
const isAppointmentActiveForVideo = (row: any) => !!activeAppointment(row)
|
||||
|
||||
/** 已预约、已过号可取消(后端同步限制),针对行上主字段 */
|
||||
const canCancelAppointmentRow = (row: any) => {
|
||||
@@ -1962,17 +1984,18 @@ const submitFillIdCard = async () => {
|
||||
}
|
||||
|
||||
// 生成视频二维码(跳转登录页)- 仅已预约(1)可生成
|
||||
const handleVideoQRCode = async (row: any) => {
|
||||
if (!isAppointmentActiveForVideo(row)) {
|
||||
feedback.msgWarning('仅「已预约」状态可生成视频二维码')
|
||||
return
|
||||
}
|
||||
if (!row.patient_id) {
|
||||
feedback.msgWarning('患者信息不完整')
|
||||
return
|
||||
}
|
||||
lastQRCodeType.value = 'video'
|
||||
currentQRCodePatient.value = row
|
||||
const handleVideoQRCode = async (row: any) => {
|
||||
const qrcodeRow = activeAppointmentRow(row)
|
||||
if (!qrcodeRow) {
|
||||
feedback.msgWarning('仅「已预约」状态可生成视频二维码')
|
||||
return
|
||||
}
|
||||
if (!qrcodeRow.patient_id) {
|
||||
feedback.msgWarning('患者信息不完整')
|
||||
return
|
||||
}
|
||||
lastQRCodeType.value = 'video'
|
||||
currentQRCodePatient.value = qrcodeRow
|
||||
qrcodeDialogVisible.value = true
|
||||
qrcodeLoading.value = true
|
||||
qrcodeUrl.value = ''
|
||||
@@ -1983,11 +2006,11 @@ const handleVideoQRCode = async (row: any) => {
|
||||
feedback.msgError('小程序未配置,请先配置小程序信息')
|
||||
qrcodeDialogVisible.value = false
|
||||
return
|
||||
}
|
||||
const result = await generateMiniProgramQrcode({
|
||||
doctor_id: row.appointment_doctor_id,
|
||||
diagnosis_id: row.appointment_doctor_id,
|
||||
patient_id: row.patient_id,
|
||||
}
|
||||
const result = await generateMiniProgramQrcode({
|
||||
doctor_id: qrcodeRow.appointment_doctor_id,
|
||||
diagnosis_id: qrcodeRow.appointment_doctor_id,
|
||||
patient_id: qrcodeRow.patient_id,
|
||||
share_user_id: userStore.userInfo?.id || '',
|
||||
mini_program_path: 'pages/login/login'
|
||||
})
|
||||
@@ -2004,17 +2027,18 @@ const handleVideoQRCode = async (row: any) => {
|
||||
}
|
||||
|
||||
// 生成确认诊单二维码
|
||||
const handleMiniProgramQRCode = async (row: any) => {
|
||||
if (!isAppointmentActiveForVideo(row)) {
|
||||
feedback.msgWarning('仅「已预约」状态可使用诊单二维码')
|
||||
return
|
||||
}
|
||||
if (!row.patient_id) {
|
||||
feedback.msgWarning('患者信息不完整')
|
||||
return
|
||||
}
|
||||
lastQRCodeType.value = 'confirm'
|
||||
currentQRCodePatient.value = row
|
||||
const handleMiniProgramQRCode = async (row: any) => {
|
||||
const qrcodeRow = activeAppointmentRow(row)
|
||||
if (!qrcodeRow) {
|
||||
feedback.msgWarning('仅「已预约」状态可使用诊单二维码')
|
||||
return
|
||||
}
|
||||
if (!qrcodeRow.patient_id) {
|
||||
feedback.msgWarning('患者信息不完整')
|
||||
return
|
||||
}
|
||||
lastQRCodeType.value = 'confirm'
|
||||
currentQRCodePatient.value = qrcodeRow
|
||||
qrcodeDialogVisible.value = true
|
||||
qrcodeLoading.value = true
|
||||
qrcodeUrl.value = ''
|
||||
@@ -2033,11 +2057,11 @@ const handleMiniProgramQRCode = async (row: any) => {
|
||||
// 获取当前登录用户信息
|
||||
const currentUser = userStore.userInfo
|
||||
|
||||
// 调用生成二维码接口
|
||||
const result = await generateMiniProgramQrcode({
|
||||
diagnosis_id: row.id,
|
||||
doctor_id: row.appointment_doctor_id,
|
||||
patient_id: row.patient_id,
|
||||
// 调用生成二维码接口
|
||||
const result = await generateMiniProgramQrcode({
|
||||
diagnosis_id: qrcodeRow.id,
|
||||
doctor_id: qrcodeRow.appointment_doctor_id,
|
||||
patient_id: qrcodeRow.patient_id,
|
||||
share_user_id: currentUser?.id || ''
|
||||
})
|
||||
|
||||
|
||||
@@ -946,8 +946,28 @@ const appointmentRowClass = (row: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const isAppointmentActiveForVideo = (row: any) =>
|
||||
row.has_appointment && Number(row.appointment_status) === 1
|
||||
/**
|
||||
* 同一诊单可能同时有已完成的旧挂号和已预约的新挂号,二维码应使用明细里的有效预约。
|
||||
*/
|
||||
const activeAppointment = (row: any) =>
|
||||
appointmentRows(row).find((apt: any) => Number(apt?.status) === 1) ?? null
|
||||
|
||||
const activeAppointmentRow = (row: any) => {
|
||||
const apt = activeAppointment(row)
|
||||
if (!apt) return null
|
||||
|
||||
return {
|
||||
...row,
|
||||
has_appointment: 1,
|
||||
appointment_id: apt.id,
|
||||
appointment_status: apt.status,
|
||||
appointment_doctor_id: apt.doctor_id,
|
||||
appointment_doctor_name: apt.doctor_name,
|
||||
appointment_time_text: apt.time_text
|
||||
}
|
||||
}
|
||||
|
||||
const isAppointmentActiveForVideo = (row: any) => !!activeAppointment(row)
|
||||
|
||||
const canCancelAppointmentRow = (row: any) => {
|
||||
const s = Number(row.appointment_status)
|
||||
@@ -1241,13 +1261,14 @@ const qrcodeAppointmentTimeText = computed(() => {
|
||||
return p.appointment_time_text || '—'
|
||||
})
|
||||
|
||||
const handleVideoQRCode = async (row: any) => {
|
||||
if (!isAppointmentActiveForVideo(row)) {
|
||||
feedback.msgWarning('仅「已预约」状态可生成视频二维码'); return
|
||||
}
|
||||
if (!row.patient_id) { feedback.msgWarning('患者信息不完整'); return }
|
||||
lastQRCodeType.value = 'video'
|
||||
currentQRCodePatient.value = row
|
||||
const handleVideoQRCode = async (row: any) => {
|
||||
const qrcodeRow = activeAppointmentRow(row)
|
||||
if (!qrcodeRow) {
|
||||
feedback.msgWarning('仅「已预约」状态可生成视频二维码'); return
|
||||
}
|
||||
if (!qrcodeRow.patient_id) { feedback.msgWarning('患者信息不完整'); return }
|
||||
lastQRCodeType.value = 'video'
|
||||
currentQRCodePatient.value = qrcodeRow
|
||||
qrcodeDialogVisible.value = true
|
||||
qrcodeLoading.value = true
|
||||
qrcodeUrl.value = ''
|
||||
@@ -1258,11 +1279,11 @@ const handleVideoQRCode = async (row: any) => {
|
||||
feedback.msgError('小程序未配置')
|
||||
qrcodeDialogVisible.value = false
|
||||
return
|
||||
}
|
||||
const result = await generateMiniProgramQrcode({
|
||||
doctor_id: row.appointment_doctor_id,
|
||||
diagnosis_id: row.appointment_doctor_id,
|
||||
patient_id: row.patient_id,
|
||||
}
|
||||
const result = await generateMiniProgramQrcode({
|
||||
doctor_id: qrcodeRow.appointment_doctor_id,
|
||||
diagnosis_id: qrcodeRow.appointment_doctor_id,
|
||||
patient_id: qrcodeRow.patient_id,
|
||||
share_user_id: userStore.userInfo?.id || '',
|
||||
mini_program_path: 'pages/login/login'
|
||||
})
|
||||
@@ -1275,13 +1296,14 @@ const handleVideoQRCode = async (row: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleMiniProgramQRCode = async (row: any) => {
|
||||
if (!isAppointmentActiveForVideo(row)) {
|
||||
feedback.msgWarning('仅「已预约」状态可使用诊单二维码'); return
|
||||
}
|
||||
if (!row.patient_id) { feedback.msgWarning('患者信息不完整'); return }
|
||||
lastQRCodeType.value = 'confirm'
|
||||
currentQRCodePatient.value = row
|
||||
const handleMiniProgramQRCode = async (row: any) => {
|
||||
const qrcodeRow = activeAppointmentRow(row)
|
||||
if (!qrcodeRow) {
|
||||
feedback.msgWarning('仅「已预约」状态可使用诊单二维码'); return
|
||||
}
|
||||
if (!qrcodeRow.patient_id) { feedback.msgWarning('患者信息不完整'); return }
|
||||
lastQRCodeType.value = 'confirm'
|
||||
currentQRCodePatient.value = qrcodeRow
|
||||
qrcodeDialogVisible.value = true
|
||||
qrcodeLoading.value = true
|
||||
qrcodeUrl.value = ''
|
||||
@@ -1292,11 +1314,11 @@ const handleMiniProgramQRCode = async (row: any) => {
|
||||
feedback.msgError('小程序未配置')
|
||||
qrcodeDialogVisible.value = false
|
||||
return
|
||||
}
|
||||
const result = await generateMiniProgramQrcode({
|
||||
diagnosis_id: row.id,
|
||||
doctor_id: row.appointment_doctor_id,
|
||||
patient_id: row.patient_id,
|
||||
}
|
||||
const result = await generateMiniProgramQrcode({
|
||||
diagnosis_id: qrcodeRow.id,
|
||||
doctor_id: qrcodeRow.appointment_doctor_id,
|
||||
patient_id: qrcodeRow.patient_id,
|
||||
share_user_id: userStore.userInfo?.id || ''
|
||||
})
|
||||
if (result?.qrcode_url) qrcodeUrl.value = result.qrcode_url
|
||||
|
||||
Reference in New Issue
Block a user