Files
xk-doctor-wx/subPackages/sub_platform_admin/input/InputAuditSheet.vue
2026-06-05 12:28:36 +08:00

351 lines
9.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<u-popup v-model="visible" mode="bottom" border-radius="24" :safe-area-inset-bottom="true">
<view class="sheet">
<view class="sheet-header">
<text class="sheet-title">{{ sheetTitle }}</text>
<text class="sheet-close" @click="close">关闭</text>
</view>
<scroll-view scroll-y class="sheet-scroll">
<view class="field-block">
<text class="field-label">审核结果</text>
<view class="radio-row">
<view
class="radio-item"
:class="{ active: auditStatus === 1 }"
@click="auditStatus = 1"
>审核通过</view>
<view
class="radio-item reject"
:class="{ active: auditStatus === 2 }"
@click="auditStatus = 2"
>审核拒绝</view>
</view>
</view>
<template v-if="inputType === 'store' && auditStatus === 1">
<view class="field-block">
<text class="field-label required">ERP ID</text>
<input v-model="erpId" class="field-input" placeholder="审核通过时必填" />
</view>
<view class="field-block">
<text class="field-label">MES ID</text>
<input v-model="mesId" class="field-input" placeholder="可选,煎药中心编码" />
</view>
<view class="field-block">
<view class="field-label-row">
<text class="field-label">一并审核关联医生可选</text>
<view v-if="pendingDoctorIds.length" class="link-actions">
<text class="link-btn" @click="selectAllPending">全选</text>
<text class="link-btn" @click="clearDoctors">取消全选</text>
</view>
</view>
<view v-if="!allDoctors.length" class="hint">暂无关联医生预填</view>
<view v-else class="doctor-check-list">
<view
v-for="doc in allDoctors"
:key="doc.id"
class="doctor-check-item"
:class="{ disabled: !isDoctorPending(doc) }"
@click="toggleDoctor(doc)"
>
<view class="check-box" :class="{ checked: isDoctorSelected(doc.id), disabled: !isDoctorPending(doc) }">
<text v-if="isDoctorSelected(doc.id)"></text>
</view>
<view class="doctor-check-body">
<text class="doctor-check-name">{{ doc.name || '-' }}</text>
<text class="doctor-check-meta">{{ doctorMetaText(doc) }}</text>
<text class="doctor-check-status">{{ doctorStatusText(doc.status) }}</text>
</view>
</view>
</view>
</view>
</template>
<view class="field-block">
<text class="field-label">审核备注</text>
<textarea
v-model="auditRemark"
class="field-textarea"
:placeholder="auditStatus === 2 ? '请输入拒绝原因(可选)' : '请输入审核备注(可选)'"
maxlength="500"
/>
</view>
</scroll-view>
<view class="sheet-footer">
<button class="footer-btn cancel" @click="close">取消</button>
<button class="footer-btn confirm" :loading="submitting" @click="submit">确认审核</button>
</view>
</view>
</u-popup>
</template>
<script>
import { inputStatusText } from '@/subPackages/sub_salesperson/common/inputDetailFields.js'
function isDoctorPending(doc) {
return Number(doc?.status) === 0
}
export default {
name: 'InputAuditSheet',
props: {
value: { type: Boolean, default: false },
inputType: { type: String, default: 'store' },
recordId: { type: Number, default: 0 },
info: { type: Object, default: () => ({}) },
defaultStatus: { type: Number, default: 1 },
},
data() {
return {
auditStatus: 1,
auditRemark: '',
erpId: '',
mesId: '',
selectedDoctorIds: [],
submitting: false,
}
},
computed: {
visible: {
get() { return this.value },
set(v) { this.$emit('input', v) },
},
sheetTitle() {
return this.inputType === 'doctor' ? '审核医生预填' : '审核录入信息'
},
allDoctors() {
const list = this.info?.doctor_inputs ?? this.info?.doctorInputs ?? []
return Array.isArray(list) ? list : []
},
pendingDoctorIds() {
return this.allDoctors
.filter(isDoctorPending)
.map((d) => Number(d.id))
.filter((id) => id > 0)
},
},
watch: {
value(open) {
if (open) this.resetForm()
},
auditStatus(v) {
if (v !== 1) {
this.selectedDoctorIds = []
} else if (this.pendingDoctorIds.length) {
this.selectedDoctorIds = [...this.pendingDoctorIds]
}
},
},
methods: {
isDoctorPending,
resetForm() {
this.auditStatus = this.defaultStatus === 2 ? 2 : 1
this.auditRemark = ''
this.erpId = this.info?.erp_id != null ? String(this.info.erp_id) : ''
this.mesId = this.info?.mes_id != null ? String(this.info.mes_id) : ''
this.selectedDoctorIds = this.pendingDoctorIds.length ? [...this.pendingDoctorIds] : []
this.submitting = false
},
close() {
this.visible = false
},
selectAllPending() {
this.selectedDoctorIds = [...this.pendingDoctorIds]
},
clearDoctors() {
this.selectedDoctorIds = []
},
isDoctorSelected(id) {
return this.selectedDoctorIds.includes(Number(id))
},
toggleDoctor(doc) {
if (!isDoctorPending(doc)) return
const id = Number(doc.id)
if (!id) return
const idx = this.selectedDoctorIds.indexOf(id)
if (idx >= 0) this.selectedDoctorIds.splice(idx, 1)
else this.selectedDoctorIds.push(id)
},
doctorMetaText(doc) {
const depart = doc.depart?.name || ''
const title = doc.titleInfo?.name || doc.title_info?.name || ''
return [depart, title].filter(Boolean).join(' · ') || '-'
},
doctorStatusText(status) {
return inputStatusText(status)
},
buildPayload() {
const payload = {
id: this.recordId,
status: this.auditStatus,
audit_remark: this.auditRemark.trim(),
}
if (this.inputType === 'store' && this.auditStatus === 1) {
payload.erp_id = this.erpId.trim()
if (this.mesId.trim()) payload.mes_id = this.mesId.trim()
if (this.selectedDoctorIds.length) payload.doctor_input_ids = [...this.selectedDoctorIds]
}
return payload
},
validate() {
if (this.inputType === 'store' && this.auditStatus === 1 && !this.erpId.trim()) {
uni.showToast({ title: '审核通过时请填写 ERP ID', icon: 'none' })
return false
}
return true
},
submit() {
if (!this.validate()) return
this.submitting = true
this.$emit('confirm', this.buildPayload(), () => {
this.submitting = false
})
},
},
}
</script>
<style scoped>
.sheet {
background: #fff;
max-height: 85vh;
display: flex;
flex-direction: column;
}
.sheet-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 28rpx 32rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.sheet-title { font-size: 32rpx; font-weight: 600; color: #1d2129; }
.sheet-close { font-size: 28rpx; color: #6acdbb; }
.sheet-scroll {
max-height: 60vh;
padding: 16rpx 32rpx 24rpx;
box-sizing: border-box;
}
.field-block { margin-bottom: 28rpx; }
.field-label {
display: block;
font-size: 28rpx;
color: #1d2129;
font-weight: 600;
margin-bottom: 16rpx;
}
.field-label.required::after { content: ' *'; color: #f53f3f; }
.field-label-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16rpx;
}
.link-actions { display: flex; gap: 16rpx; }
.link-btn { font-size: 24rpx; color: #6acdbb; }
.field-input {
width: 100%;
height: 72rpx;
padding: 0 20rpx;
border: 1rpx solid #e5e6eb;
border-radius: 12rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.field-textarea {
width: 100%;
min-height: 160rpx;
padding: 16rpx 20rpx;
border: 1rpx solid #e5e6eb;
border-radius: 12rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.radio-row { display: flex; gap: 16rpx; }
.radio-item {
flex: 1;
text-align: center;
padding: 20rpx 0;
border: 1rpx solid #e5e6eb;
border-radius: 12rpx;
font-size: 28rpx;
color: #4e5969;
}
.radio-item.active {
border-color: #6acdbb;
color: #6acdbb;
background: #f0faf8;
}
.radio-item.reject.active {
border-color: #f53f3f;
color: #f53f3f;
background: #fff2f0;
}
.hint { font-size: 26rpx; color: #86909c; }
.doctor-check-list { display: flex; flex-direction: column; gap: 12rpx; }
.doctor-check-item {
display: flex;
align-items: flex-start;
padding: 16rpx;
background: #f7f8fa;
border-radius: 12rpx;
}
.doctor-check-item.disabled { opacity: 0.55; }
.check-box {
width: 36rpx;
height: 36rpx;
border: 2rpx solid #c9cdd4;
border-radius: 8rpx;
margin-right: 16rpx;
margin-top: 6rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 22rpx;
color: #fff;
flex-shrink: 0;
}
.check-box.checked { background: #6acdbb; border-color: #6acdbb; }
.check-box.disabled { background: #f2f3f5; }
.doctor-check-body { flex: 1; min-width: 0; }
.doctor-check-name {
display: block;
font-size: 28rpx;
font-weight: 600;
color: #1d2129;
}
.doctor-check-meta {
display: block;
font-size: 24rpx;
color: #86909c;
margin-top: 6rpx;
}
.doctor-check-status {
display: block;
font-size: 24rpx;
color: #6acdbb;
margin-top: 4rpx;
}
.sheet-footer {
display: flex;
gap: 16rpx;
padding: 20rpx 32rpx calc(20rpx + env(safe-area-inset-bottom));
border-top: 1rpx solid #f0f0f0;
}
.footer-btn {
flex: 1;
font-size: 28rpx;
height: 80rpx;
line-height: 80rpx;
border-radius: 12rpx;
}
.footer-btn.cancel {
background: #f2f3f5;
color: #4e5969;
}
.footer-btn.confirm {
background: #6acdbb;
color: #fff;
}
</style>