351 lines
9.9 KiB
Vue
351 lines
9.9 KiB
Vue
<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>
|