| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- <template>
- <view class="filing-page">
- <view v-if="loading" class="page-loading">
- <wd-loading size="48rpx" />
- <text>备案信息加载中...</text>
- </view>
- <template v-else>
- <view class="invitation-card">
- <view class="invitation-card__title">备案邀请</view>
- <view class="invitation-card__content">
- <text v-if="entName" class="company-name">【{{ entName }}】</text>
- <text>向您发起了备案邀请,请提交您的备案信息。</text>
- </view>
- </view>
- <view class="form-card">
- <view class="form-row form-row--record">
- <view class="form-label">医药代表资质备案号:</view>
- <view class="form-control form-control--column">
- <view class="optional-tag">没有备案号可以不填</view>
- <input
- v-model="form.filingNo"
- class="record-input"
- :maxlength="50"
- placeholder="填写备案号"
- placeholder-class="form-placeholder"
- />
- </view>
- </view>
- <view class="form-row" @click="openEducationPicker">
- <view class="form-label">学历:</view>
- <view class="form-control">
- <text :class="form.degreeName ? 'form-value' : 'form-placeholder'">
- {{ form.degreeName || '请选择学历' }}
- </text>
- <wd-icon name="right" size="32rpx" color="#a9afb8" />
- </view>
- </view>
- <view class="form-row" @click="openMajorPicker">
- <view class="form-label">所学专业类别:</view>
- <view class="form-control">
- <text :class="form.majorName ? 'form-value' : 'form-placeholder'">
- {{ form.majorName || '请选择专业类别' }}
- </text>
- <wd-icon name="right" size="32rpx" color="#a9afb8" />
- </view>
- </view>
- <view class="form-row" @click="openAreaPicker">
- <view class="form-label">所在区域:</view>
- <view class="form-control">
- <text :class="form.areaName ? 'form-value' : 'form-placeholder'">
- {{ form.areaName || '请选择区域' }}
- </text>
- <wd-icon name="right" size="32rpx" color="#a9afb8" />
- </view>
- </view>
- <view class="form-row form-row--last" @click="openDrugPicker">
- <view class="form-label">推广药品:</view>
- <view class="form-control">
- <text class="form-value">{{ selectedDrugText }}</text>
- <wd-icon name="right" size="32rpx" color="#a9afb8" />
- </view>
- </view>
- </view>
- <view class="submit-section">
- <button class="submit-button" :disabled="submitting" @click="submit">
- {{ submitting ? '提交中...' : '提交备案' }}
- </button>
- </view>
- </template>
- <wd-picker
- v-model:visible="educationPickerVisible"
- title="选择学历"
- :columns="educationList"
- label-key="label"
- value-key="value"
- root-portal
- @confirm="confirmEducation"
- />
- <wd-picker
- v-model:visible="majorPickerVisible"
- title="选择专业类别"
- :columns="majorList"
- label-key="label"
- value-key="value"
- root-portal
- @confirm="confirmMajor"
- />
- <wd-cascader
- v-model="areaPickerValue"
- v-model:visible="areaPickerVisible"
- title="选择所在区域"
- :options="areaOptions"
- root-portal
- @confirm="confirmArea"
- />
- <wd-select-picker
- v-model="selectedDrugIds"
- v-model:visible="drugPickerVisible"
- title="选择推广药品"
- :columns="drugOptions"
- filterable
- filter-placeholder="搜索药品"
- root-portal
- />
- </view>
- </template>
- <script setup lang="ts">
- import { computed, reactive, ref } from 'vue'
- import { onLoad } from '@dcloudio/uni-app'
- import { useCascaderAreaData } from '@vant/area-data'
- import { getDictTypeApi } from '@/services/modules/common'
- import type { DictItem } from '@/services/modules/common/type'
- import {
- getUserFilingPendingDetailApi,
- submitUserFilingApi,
- } from '@/services/modules/userInfo'
- import type {
- FilingDrugId,
- FilingDrugItem,
- UserFilingSubmitRequest,
- } from '@/services/modules/userInfo/type'
- interface PageOptions {
- entTaxCode?: string
- entName?: string
- }
- interface AreaOption {
- value: string
- text: string
- children?: AreaOption[]
- isLeaf?: boolean
- }
- interface AreaConfirmEvent {
- selectedOptions?: AreaOption[]
- }
- const entTaxCode = ref('')
- const entName = ref('')
- const loading = ref(true)
- const submitting = ref(false)
- const educationPickerVisible = ref(false)
- const majorPickerVisible = ref(false)
- const areaPickerVisible = ref(false)
- const drugPickerVisible = ref(false)
- const areaPickerValue = ref<string | number>()
- const educationList = ref<DictItem[]>([])
- const majorList = ref<DictItem[]>([])
- const drugList = ref<FilingDrugItem[]>([])
- const selectedDrugIds = ref<string[]>([])
- const form = reactive({
- filingNo: '',
- degree: '',
- degreeName: '',
- majorCategory: '',
- majorName: '',
- province: '',
- provinceCode: '',
- city: '',
- cityCode: '',
- areaName: '',
- })
- const rawAreaOptions = useCascaderAreaData() as AreaOption[]
- const areaOptions = convertCityLeaf(rawAreaOptions)
- const drugOptions = computed(() =>
- drugList.value.map((item) => ({
- label: item.drug_name,
- value: String(item.drug_id),
- }))
- )
- const selectedDrugText = computed(() => {
- if (!selectedDrugIds.value.length) return '默认选择全部'
- return `已选择${selectedDrugIds.value.length}个药品`
- })
- onLoad((options?: PageOptions) => {
- entTaxCode.value = decodeQueryValue(options?.entTaxCode)
- entName.value = decodeQueryValue(options?.entName)
- if (!entTaxCode.value) {
- loading.value = false
- uni.showModal({
- title: '提示',
- content: '缺少企业税号,无法加载备案信息',
- showCancel: false,
- success() {
- uni.navigateBack()
- },
- })
- return
- }
- void initPage()
- })
- const initPage = async () => {
- loading.value = true
- try {
- const [detailRes, degreeRes, majorRes] = await Promise.all([
- getUserFilingPendingDetailApi(entTaxCode.value),
- getDictTypeApi('user_degree'),
- getDictTypeApi('user_filing_major'),
- ])
- educationList.value = degreeRes.data ?? []
- majorList.value = majorRes.data ?? []
- const detail = detailRes.data
- const record = detail.record
- entName.value = detail.drugEntName || record.drugEntName || record.deptName || entName.value
- drugList.value = detail.optionalDrugs ?? []
- // 详情仅回填备案号,其余备案字段由用户本次重新选择。
- form.filingNo = record.filingNo ?? ''
- } catch (error) {
- console.error('获取待提交备案信息失败:', error)
- } finally {
- loading.value = false
- }
- }
- const openEducationPicker = () => {
- if (showEmptyOptions(educationList.value, '暂无可选学历')) return
- educationPickerVisible.value = true
- }
- const openMajorPicker = () => {
- if (showEmptyOptions(majorList.value, '暂无可选专业类别')) return
- majorPickerVisible.value = true
- }
- const openAreaPicker = () => {
- areaPickerVisible.value = true
- }
- const openDrugPicker = () => {
- if (showEmptyOptions(drugOptions.value, '暂无可选推广药品')) return
- drugPickerVisible.value = true
- }
- const confirmEducation = (event: PickerConfirmEvent) => {
- const item = event.selectedItems[0] as DictItem | undefined
- if (!item) return
- form.degree = item.value
- form.degreeName = item.label
- }
- const confirmMajor = (event: PickerConfirmEvent) => {
- const item = event.selectedItems[0] as DictItem | undefined
- if (!item) return
- form.majorCategory = item.value
- form.majorName = item.label
- }
- const confirmArea = (event: AreaConfirmEvent) => {
- const [province, city] = event.selectedOptions ?? []
- if (!province || !city) return
- form.province = province.text
- form.provinceCode = String(province.value)
- form.city = city.text
- form.cityCode = String(city.value)
- form.areaName = `${province.text}/${city.text}`
- areaPickerValue.value = city.value
- }
- const submit = async () => {
- if (submitting.value) return
- const payload: UserFilingSubmitRequest = {
- entTaxCode: entTaxCode.value,
- filingNo: form.filingNo.trim(),
- degree: form.degree,
- majorCategory: form.majorCategory,
- province: form.province,
- provinceCode: form.provinceCode,
- city: form.city,
- cityCode: form.cityCode,
- promotionDrugIds: resolvePromotionDrugIds(),
- }
- try {
- submitting.value = true
- await submitUserFilingApi(payload)
- uni.showToast({
- title: '提交成功',
- icon: 'success',
- })
- setTimeout(() => {
- uni.navigateBack()
- }, 800)
- } catch (error) {
- console.error('提交备案失败:', error)
- submitting.value = false
- }
- }
- const resolvePromotionDrugIds = (): FilingDrugId[] => {
- if (!selectedDrugIds.value.length) {
- return drugList.value.map((item) => item.drug_id)
- }
- return [...selectedDrugIds.value]
- }
- function convertCityLeaf(list: AreaOption[]): AreaOption[] {
- return list.map((province) => ({
- ...province,
- children: province.children?.map((city) => ({
- value: city.value,
- text: city.text,
- isLeaf: true,
- })),
- }))
- }
- const showEmptyOptions = (options: unknown[], message: string): boolean => {
- if (options.length) return false
- uni.showToast({
- title: message,
- icon: 'none',
- })
- return true
- }
- const decodeQueryValue = (value?: string): string => {
- if (!value) return ''
- try {
- return decodeURIComponent(value)
- } catch {
- return value
- }
- }
- </script>
- <style lang="scss" scoped>
- .filing-page {
- min-height: 100vh;
- padding: 28rpx 24rpx calc(150rpx + env(safe-area-inset-bottom));
- box-sizing: border-box;
- background: #f5f7fa;
- }
- .page-loading {
- min-height: 60vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- gap: 20rpx;
- color: #8a93a0;
- font-size: 26rpx;
- }
- .invitation-card,
- .form-card {
- background: #ffffff;
- border-radius: 24rpx;
- box-shadow: 0 10rpx 30rpx rgba(31, 45, 61, 0.06);
- }
- .invitation-card {
- padding: 30rpx;
- margin-bottom: 24rpx;
- }
- .invitation-card__title {
- margin-bottom: 14rpx;
- color: #1f2329;
- font-size: 32rpx;
- font-weight: 600;
- }
- .invitation-card__content {
- color: #68707c;
- font-size: 28rpx;
- line-height: 44rpx;
- }
- .company-name {
- color: #30343b;
- font-weight: 600;
- }
- .form-card {
- padding: 0 30rpx;
- overflow: hidden;
- }
- .form-row {
- min-height: 104rpx;
- display: flex;
- align-items: center;
- border-bottom: 1rpx solid #eeeeee;
- }
- .form-row--record {
- min-height: 140rpx;
- }
- .form-row--last {
- border-bottom: none;
- }
- .form-label {
- width: 230rpx;
- flex-shrink: 0;
- color: #4f5661;
- font-size: 28rpx;
- }
- .form-control {
- min-width: 0;
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 10rpx;
- text-align: right;
- }
- .form-control--column {
- flex-direction: column;
- align-items: flex-end;
- justify-content: center;
- }
- .optional-tag {
- padding: 5rpx 14rpx;
- border-radius: 30rpx;
- background: #edf3ff;
- color: #537cf3;
- font-size: 22rpx;
- line-height: 30rpx;
- }
- .record-input {
- width: 100%;
- height: 54rpx;
- color: #30343b;
- font-size: 28rpx;
- line-height: 54rpx;
- text-align: right;
- }
- .form-value,
- .form-placeholder {
- max-width: 370rpx;
- overflow: hidden;
- font-size: 28rpx;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
- .form-value {
- color: #30343b;
- }
- .form-placeholder {
- color: #a9afb8;
- }
- .submit-section {
- position: fixed;
- z-index: 20;
- left: 0;
- right: 0;
- bottom: 0;
- padding: 20rpx 36rpx calc(20rpx + env(safe-area-inset-bottom));
- background: rgba(255, 255, 255, 0.96);
- box-shadow: 0 -8rpx 24rpx rgba(31, 45, 61, 0.08);
- }
- .submit-button {
- width: 100%;
- height: 88rpx;
- padding: 0;
- border: none;
- border-radius: 44rpx;
- background: #537cf3;
- color: #ffffff;
- font-size: 32rpx;
- font-weight: 600;
- line-height: 88rpx;
- &::after {
- border: none;
- }
- &[disabled] {
- opacity: 0.65;
- color: #ffffff;
- }
- }
- </style>
|