Browse Source

完成任务类型限制功能

yuanmingze 1 tháng trước cách đây
mục cha
commit
046860d132

+ 134 - 15
src/pages-common/entity-selector/index.vue

@@ -15,10 +15,22 @@
         />
       </view>
 
-      <button class="add-btn" @click="openAddDialog">新增</button>
+      <button v-if="!isSurveyTarget" class="add-btn" @click="openAddDialog">新增</button>
     </view>
 
-    <view class="list-wrapper">
+    <view v-if="isSurveyTarget" class="entity-tabs">
+      <view
+        v-for="tab in surveyTargetTabs"
+        :key="tab.alias"
+        class="entity-tab"
+        :class="{ 'entity-tab--active': activeEntityAlias === tab.alias }"
+        @click="switchSurveyTargetTab(tab.alias)"
+      >
+        {{ tab.label }}
+      </view>
+    </view>
+
+    <view class="list-wrapper" :class="{ 'list-wrapper--with-tabs': isSurveyTarget }">
       <view v-for="item in list" :key="item.id" class="list-item" @click="selectItem(item)">
         <view class="radio" :class="{ 'radio--active': selected?.id === item.id }">
           <view v-if="selected?.id === item.id" class="radio__dot" />
@@ -104,18 +116,22 @@ import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
 import { debounce } from '@/plugins/debounce'
 
 import {
+  getDistributionByNameApi,
   getHospitalByNameApi,
   getWmDaPharmacyByNameApi,
+  listDistributionByNameApi,
   listHospitalByNameApi,
   listWmDaPharmacyByNameApi,
 } from '@/services/modules/task/entitySelector'
 import type {
+  DistributionItem,
   EntitySelectorRequest,
   HospitalItem,
   PharmacyItem,
+  SurveyTargetItem,
 } from '@/services/modules/task/entitySelector/type'
 
-const aliasConfig = {
+const entityAliasConfig = {
   pharmacyName: {
     entityName: '药店',
     eventName: 'pharmacyNameSelect',
@@ -124,16 +140,28 @@ const aliasConfig = {
     entityName: '医院',
     eventName: 'yymcSelect',
   },
+  companyName: {
+    entityName: '商业公司',
+    eventName: 'companySelect',
+  },
 } as const
 
-type PageAlias = keyof typeof aliasConfig
-type EntityItem = PharmacyItem | HospitalItem
+type EntityAlias = keyof typeof entityAliasConfig
+type PageAlias = EntityAlias | 'surveyTarget'
+type EntityItem = PharmacyItem | HospitalItem | DistributionItem
+
+const surveyTargetTabs: ReadonlyArray<{ alias: EntityAlias; label: string }> = [
+  { alias: 'yymc', label: '选择医院' },
+  { alias: 'pharmacyName', label: '选择药店(含连锁)' },
+  { alias: 'companyName', label: '选择商业公司' },
+]
 
 interface PageQuery {
   alias?: string
 }
 
 const pageAlias = ref<PageAlias>('pharmacyName')
+const activeEntityAlias = ref<EntityAlias>('yymc')
 const keyword = ref('')
 const list = ref<EntityItem[]>([])
 const selected = ref<EntityItem>()
@@ -151,25 +179,37 @@ const addError = ref('')
 
 let requestVersion = 0
 
-const entityName = computed(() => aliasConfig[pageAlias.value].entityName)
+const isSurveyTarget = computed(() => pageAlias.value === 'surveyTarget')
+const currentEntityAlias = computed<EntityAlias>(() =>
+  isSurveyTarget.value ? activeEntityAlias.value : (pageAlias.value as EntityAlias)
+)
+const entityName = computed(() => entityAliasConfig[currentEntityAlias.value].entityName)
 const searchPlaceholder = computed(() => `搜索${entityName.value}名称`)
 const addTitle = computed(() => `新增${entityName.value}`)
 const addPlaceholder = computed(() => `请输入${entityName.value}名称`)
 
 const getItemName = (item: EntityItem): string => {
-  return 'yymc' in item ? item.yymc : item.pharmacyName
+  const surveyTargetItem: SurveyTargetItem = item
+
+  return surveyTargetItem.yymc || surveyTargetItem.gsmc || surveyTargetItem.pharmacyName || ''
 }
 
 const requestEntityPage = async (
   params: EntitySelectorRequest
 ): Promise<{ records: EntityItem[]; pages: number }> => {
-  if (pageAlias.value === 'pharmacyName') {
+  if (currentEntityAlias.value === 'pharmacyName') {
     const { data } = await listWmDaPharmacyByNameApi(params)
 
     return data
   }
 
-  const { data } = await listHospitalByNameApi(params)
+  if (currentEntityAlias.value === 'yymc') {
+    const { data } = await listHospitalByNameApi(params)
+
+    return data
+  }
+
+  const { data } = await listDistributionByNameApi(params)
 
   return data
 }
@@ -253,8 +293,11 @@ const getOpenerEventChannel = () => {
 
 const emitSelectedItem = (item: EntityItem | string) => {
   const eventChannel = getOpenerEventChannel()
+  const eventName = isSurveyTarget.value
+    ? 'surveyTargetSelect'
+    : entityAliasConfig[currentEntityAlias.value].eventName
 
-  eventChannel?.emit(aliasConfig[pageAlias.value].eventName, item)
+  eventChannel?.emit(eventName, item)
 }
 
 const selectItem = (item: EntityItem) => {
@@ -264,6 +307,17 @@ const selectItem = (item: EntityItem) => {
   uni.navigateBack()
 }
 
+const switchSurveyTargetTab = (alias: EntityAlias) => {
+  if (alias === activeEntityAlias.value) {
+    return
+  }
+
+  activeEntityAlias.value = alias
+  keyword.value = ''
+  selected.value = undefined
+  void loadList(true)
+}
+
 const openAddDialog = () => {
   addName.value = ''
   addError.value = ''
@@ -298,10 +352,15 @@ const confirmAdd = () => {
 }
 
 const entityAddSubmit = async (name: string) => {
-  const existingItem =
-    pageAlias.value === 'pharmacyName'
-      ? (await getWmDaPharmacyByNameApi(name)).data
-      : (await getHospitalByNameApi(name)).data
+  let existingItem: EntityItem | null
+
+  if (currentEntityAlias.value === 'pharmacyName') {
+    existingItem = (await getWmDaPharmacyByNameApi(name)).data
+  } else if (currentEntityAlias.value === 'yymc') {
+    existingItem = (await getHospitalByNameApi(name)).data
+  } else {
+    existingItem = (await getDistributionByNameApi(name)).data
+  }
 
   if (existingItem) {
     uni.showToast({
@@ -325,7 +384,21 @@ const entityAddSubmit = async (name: string) => {
 }
 
 onLoad((query?: PageQuery) => {
-  pageAlias.value = (query?.alias as PageAlias) ?? 'pharmacyName'
+  const alias = query?.alias
+
+  pageAlias.value =
+    alias === 'surveyTarget' ||
+    alias === 'pharmacyName' ||
+    alias === 'yymc' ||
+    alias === 'companyName'
+      ? alias
+      : 'pharmacyName'
+
+  if (isSurveyTarget.value) {
+    uni.setNavigationBarTitle({
+      title: '选择调查对象',
+    })
+  }
 
   void loadList(true)
 })
@@ -404,11 +477,57 @@ onPullDownRefresh(async () => {
   }
 }
 
+.entity-tabs {
+  position: fixed;
+  top: 120rpx;
+  right: 0;
+  left: 0;
+  z-index: 99;
+  display: flex;
+  height: 96rpx;
+  padding: 0 20rpx;
+  box-sizing: border-box;
+  background: #fff;
+  border-bottom: 1rpx solid #f2f3f5;
+}
+
+.entity-tab {
+  position: relative;
+  display: flex;
+  flex: 1;
+  align-items: center;
+  justify-content: center;
+  min-width: 0;
+  font-size: 30rpx;
+  color: #999;
+  white-space: nowrap;
+}
+
+.entity-tab--active {
+  font-weight: 500;
+  color: #3c9cff;
+
+  &::after {
+    position: absolute;
+    right: 24rpx;
+    bottom: 0;
+    left: 24rpx;
+    height: 6rpx;
+    background: #3c9cff;
+    border-radius: 3rpx;
+    content: '';
+  }
+}
+
 .list-wrapper {
   padding-top: 120rpx;
   padding-bottom: env(safe-area-inset-bottom);
 }
 
+.list-wrapper--with-tabs {
+  padding-top: 216rpx;
+}
+
 .list-item {
   display: flex;
   align-items: center;

+ 30 - 24
src/pages-task/task-form/components/SingleSelect.vue

@@ -101,38 +101,44 @@ const cellValue = computed(() => {
   return label.value === undefined ? '' : String(label.value)
 })
 
-/**
- * 同步外部 value
- *
- * 1. value 存在:
- *    - 同步 pickerValue
- *    - 根据 options 自动补充 label
- *
- * 2. value 清空:
- *    - 清空 pickerValue
- *    - 清空 label
- */
 watch(
-  value,
-  (currentValue) => {
-    if (currentValue === undefined || currentValue === '') {
-      pickerValue.value = []
-      label.value = ''
-      return
-    }
+  [value, label, pickerOptions],
+  ([currentValue, currentLabel, currentOptions]) => {
+    /**
+     * value 存在,以 value 为准。
+     */
+    if (currentValue !== undefined && currentValue !== '') {
+      const valueString = String(currentValue)
 
-    const valueString = String(currentValue)
+      pickerValue.value = [valueString]
 
-    pickerValue.value = [valueString]
+      const selectedOption = currentOptions.find((item) => String(item.value) === valueString)
+
+      if (selectedOption && currentLabel !== selectedOption.label) {
+        label.value = selectedOption.label
+      }
+
+      return
+    }
 
     /**
-     * value 回显时自动匹配 label
+     * 只有 label 时,通过 label 反查 value。
      */
-    const selectedOption = pickerOptions.value.find((item) => String(item.value) === valueString)
+    if (currentLabel !== undefined && currentLabel !== '') {
+      const selectedOption = currentOptions.find(
+        (item) => String(item.label) === String(currentLabel)
+      )
 
-    if (selectedOption && label.value !== selectedOption.label) {
-      label.value = selectedOption.label
+      if (selectedOption) {
+        const selectedValue = String(selectedOption.value)
+
+        pickerValue.value = [selectedValue]
+        value.value = selectedOption.value
+      }
+
+      return
     }
+    pickerValue.value = []
   },
   {
     immediate: true,

+ 2 - 2
src/pages-task/task-form/composables/useTaskFormAction.ts

@@ -17,7 +17,7 @@ interface UseTaskFormActionOptions {
 
 type FormAction = 'save' | 'submit'
 
-const PACKAGE_FIELD_ALIAS = 'scorePackage'
+const PACKAGE_FIELD_ALIASES = new Set(['approvalResult', 'scorePackage'])
 const IMAGE_FIELD_TYPE = 'img'
 const SUCCESS_TOAST_DURATION = 3000
 
@@ -115,7 +115,7 @@ export const useTaskFormAction = ({
   const duplicateImageList = ref<string[]>([])
 
   const findPackageField = (): TaskFieldConfigViewItem | undefined => {
-    return taskFieldConfigList.value.find((field) => field.alias === PACKAGE_FIELD_ALIAS)
+    return taskFieldConfigList.value.find((field) => PACKAGE_FIELD_ALIASES.has(field.alias ?? ''))
   }
 
   const getPackageId = (): string => {

+ 148 - 9
src/pages-task/task-form/composables/useTaskSelectHandlers.ts

@@ -1,6 +1,12 @@
 import type { Ref } from 'vue'
 
-import type { HospitalItem, PharmacyItem } from '@/services/modules/task/entitySelector/type'
+import { getPackageListByTaskTypeApi } from '@/services/modules/information'
+import type {
+  DistributionItem,
+  HospitalItem,
+  PharmacyItem,
+  SurveyTargetItem,
+} from '@/services/modules/task/entitySelector/type'
 import { getListDrugTableApi } from '@/services/modules/task/taskFrom/index'
 
 import type {
@@ -10,6 +16,7 @@ import type {
   TaskFieldConfigViewItem,
   TaskFieldOption,
 } from './useTaskForm'
+import { serializeTaskFieldOptions } from './useTaskForm'
 
 export interface SingleSelectChangeEvent {
   previousValue: FieldValue
@@ -18,11 +25,6 @@ export interface SingleSelectChangeEvent {
   selectedItem: TaskFieldOption
 }
 
-const HOSPITAL_FIELD_SOURCE_MAP: Readonly<Record<string, keyof HospitalItem>> = {
-  yycs: 'city',
-  yydz: 'address',
-}
-
 interface UseTaskSelectHandlersOptions {
   taskTypeId: Ref<string>
   form: Ref<DynamicFormState>
@@ -169,6 +171,54 @@ export const useTaskSelectHandlers = ({
    * 特殊接口请求和业务校验写在这里。
    */
   const handleSingleSelectBeforeOpen = async (field: TaskFieldConfigViewItem): Promise<boolean> => {
+    if (['1', '2', '3', '4', '64'].includes(field.taskTypeId) && field.alias === 'scorePackage') {
+      const meetingTypeValue = getFieldFormValueByAlias('meetingType')
+      if (!meetingTypeValue?.value) {
+        uni.showToast({
+          title: '请先选择会议类型',
+          icon: 'none',
+        })
+        return false
+      }
+    }
+    if (['34'].includes(field.taskTypeId) && field.alias === 'scorePackage') {
+      const trainingTypeValue = getFieldFormValueByAlias('trainingType')
+      if (!trainingTypeValue?.value) {
+        uni.showToast({
+          title: '请先选择积分包',
+          icon: 'none',
+        })
+        return false
+      }
+      const res = await getPackageListByTaskTypeApi(trainingTypeValue.value)
+      setFieldOptions(field, serializeTaskFieldOptions(res.data))
+    }
+
+    if (['14', '31', '37'].includes(field.taskTypeId) && field.taskFiledValue === 'surveyTarget') {
+      const realTaskTypeIdValue = getFieldFormValueByAlias('realTaskTypeId')
+      if (!realTaskTypeIdValue?.value) {
+        uni.showToast({
+          title: '请先选择调查类别',
+          icon: 'none',
+        })
+        return false
+      }
+      uni.navigateTo({
+        url: `/pages-common/entity-selector/index?alias=surveyTarget`,
+        events: {
+          surveyTargetSelect: (selectedItem: SurveyTargetItem) => {
+            const name = selectedItem.yymc || selectedItem.gsmc || selectedItem.pharmacyName || ''
+
+            setFieldFormValueByAlias('surveyTarget', {
+              label: name,
+              value: selectedItem.id,
+            })
+          },
+        },
+      })
+      return false
+    }
+
     if (field.taskTypeId === '18' && field.alias === 'pharmacyName') {
       uni.navigateTo({
         url: `/pages-common/entity-selector/index?alias=pharmacyName`,
@@ -191,6 +241,17 @@ export const useTaskSelectHandlers = ({
       })
       return false
     }
+    if (field.taskTypeId === '16' && field.alias === 'companyName') {
+      uni.navigateTo({
+        url: `/pages-common/entity-selector/index?alias=companyName`,
+        events: {
+          companySelect: (selectedCompanyItem: DistributionItem | string) => {
+            setCompanyNameSelectEvent(selectedCompanyItem)
+          },
+        },
+      })
+      return false
+    }
     if (taskTypeId.value === '47') {
       /**
        * OTC 推广任务示例。
@@ -352,15 +413,93 @@ export const useTaskSelectHandlers = ({
       value: selectedHospitalItem.id,
     })
 
-    const address = `${selectedHospitalItem.province}-${selectedHospitalItem.city}-${selectedHospitalItem.area}`
+    const city = `${selectedHospitalItem.province}-${selectedHospitalItem.city}-${selectedHospitalItem.area}`
+    setFieldFormValueByAlias('city', {
+      label: city,
+      value: city,
+    })
     setFieldFormValueByAlias('address', {
-      label: address,
-      value: address,
+      label: selectedHospitalItem.address,
+      value: selectedHospitalItem.address,
+    })
+    setFieldFormValueByAlias('level', {
+      label: selectedHospitalItem.yygm ?? '',
+      value: undefined,
+    })
+    setFieldFormValueByAlias('ownerType', {
+      label: selectedHospitalItem.yyxz ?? '',
+      value: undefined,
+    })
+    setFieldFormValueByAlias('website', {
+      label: selectedHospitalItem.website ?? '',
+      value: selectedHospitalItem.website ?? '',
+    })
+
+    setFieldFormValueByAlias('bedNumber', {
+      label: selectedHospitalItem.ybczs ?? '',
+      value: undefined,
     })
 
     console.log('setHospitalNameSelectEvent', selectedHospitalItem)
   }
 
+  const setCompanyNameSelectEvent = (selectedCompanyItem: DistributionItem | string) => {
+    console.log('selectedCompanyItem', selectedCompanyItem)
+
+    if (typeof selectedCompanyItem === 'string') {
+      setFieldFormValueByAlias('companyName', {
+        label: selectedCompanyItem,
+        value: selectedCompanyItem,
+      })
+      return
+    }
+
+    setFieldFormValueByAlias('companyName', {
+      label: selectedCompanyItem.gsmc,
+      value: selectedCompanyItem.id,
+    })
+
+    setFieldFormValueByAlias('address', {
+      label: selectedCompanyItem.sygsdz,
+      value: selectedCompanyItem.sygsdz,
+    })
+    setFieldFormValueByAlias('gsgm', {
+      label: selectedCompanyItem.gsgm,
+      value: undefined,
+    })
+    setFieldFormValueByAlias('shyshxydm', {
+      label: selectedCompanyItem.shyshxydm,
+      value: selectedCompanyItem.shyshxydm,
+    })
+    setFieldFormValueByAlias('shyshxydm', {
+      label: selectedCompanyItem.shyshxydm,
+      value: selectedCompanyItem.shyshxydm,
+    })
+    setFieldFormValueByAlias('zczb', {
+      label: selectedCompanyItem.zczb,
+      value: selectedCompanyItem.zczb,
+    })
+    setFieldFormValueByAlias('frdb', {
+      label: selectedCompanyItem.frdb,
+      value: selectedCompanyItem.frdb,
+    })
+    setFieldFormValueByAlias('medicineTraceability', {
+      label: undefined,
+      value: selectedCompanyItem.medicineTraceability,
+    })
+    setFieldFormValueByAlias('medicineTraceabilityOther', {
+      label: selectedCompanyItem.medicineTraceabilityOther,
+      value: selectedCompanyItem.medicineTraceabilityOther,
+    })
+    setFieldFormValueByAlias('gsjj', {
+      label: selectedCompanyItem.gsjj,
+      value: selectedCompanyItem.gsjj,
+    })
+    setFieldFormValueByAlias('jyys', {
+      label: selectedCompanyItem.jyys,
+      value: selectedCompanyItem.jyys,
+    })
+  }
   return {
     handleSingleSelectBeforeOpen,
     handleSingleSelectChange,

+ 1 - 1
src/services/modules/information/index.ts

@@ -33,7 +33,7 @@ export const getAlbumByIdApi = (id: string) => {
   return http.get<AlbumPageNewItem>(`/admin/api/getAlbumById?id=${id}`)
 }
 
-export const getPackageListByTaskTypeApi = (type: string) => {
+export const getPackageListByTaskTypeApi = (type: string | number) => {
   return http.get<GetPackageListByTaskTypeResponse>(
     `/admin/api/getPackageListByTaskType`,
     { type },

+ 15 - 0
src/services/modules/task/entitySelector/index.ts

@@ -1,5 +1,7 @@
 import http from '../../../index'
 import type {
+  DistributionItem,
+  DistributionResponse,
   EntitySelectorRequest,
   HospitalItem,
   ListHospitalByNameResponse,
@@ -31,3 +33,16 @@ export const listHospitalByNameApi = (params: EntitySelectorRequest) => {
 export const getHospitalByNameApi = (name: string) => {
   return http.get<HospitalItem | null>(`/admin/wmdahospital/getHospitalByName?name=${name}`)
 }
+
+export const listDistributionByNameApi = (params: EntitySelectorRequest) => {
+  return http.get<DistributionResponse>(`/admin/wmdadistribution/listDistributionByName`, params, {
+    loading: true,
+    loadingText: '加载中...',
+  })
+}
+
+export const getDistributionByNameApi = (name: string) => {
+  return http.get<DistributionItem | null>(
+    `/admin/wmdadistribution/getDistributionByName?name=${name}`
+  )
+}

+ 51 - 0
src/services/modules/task/entitySelector/type.d.ts

@@ -20,6 +20,15 @@ export type ListWmDaPharmacyByNameResponse = EntitySelectorPageResponse<Pharmacy
 
 export type ListHospitalByNameResponse = EntitySelectorPageResponse<HospitalItem>
 
+export type DistributionResponse = EntitySelectorPageResponse<DistributionItem>
+
+export interface SurveyTargetItem {
+  id: string
+  yymc?: string
+  gsmc?: string
+  pharmacyName?: string
+}
+
 export interface PharmacyItem {
   /**
    * 主键 ID
@@ -249,3 +258,45 @@ export interface HospitalItem {
   createUser: string | number | null
   updateUser: string | number | null
 }
+
+export interface DistributionItem {
+  address: string
+  area: string
+  cgbmdjrlxfs: string
+  cgbmdjrxm: string
+  city: string
+  cjbmfzrlxfs: string | null
+  cjbmfzrxm: string | null
+  createTime: string
+  createUser: number | null
+  dataCleaing: boolean
+  delFlag: number
+  deptId: number | null
+  enableFlag: number
+  frdb: string
+  gsgm: string
+  gsjj: string
+  gsmc: string
+  gspzsbh: string
+  gszcd: string
+  id: string
+  jyys: string
+  latitude: string
+  longitude: string
+  medicineTraceability: string
+  medicineTraceabilityName: string | null
+  medicineTraceabilityOther: string
+  province: string
+  remark: string | null
+  shyshxydm: string
+  sygsdz: string
+  tenantId: number
+  updateTime: string
+  updateUser: number | null
+  xsbmdjrlxfs: string
+  xsbmdjrxm: string
+  xsbmfzrlxfs: string | null
+  xsbmfzrxm: string | null
+  zczb: string
+  zjl: string
+}