Bläddra i källkod

完成药店选择回显

yuanmingze 2 månader sedan
förälder
incheckning
954a742cc6

+ 500 - 0
src/pages-common/entity-selector/index.vue

@@ -0,0 +1,500 @@
+<template>
+  <page-meta :page-style="showAddDialog ? 'overflow:hidden;' : 'overflow:visible;'" />
+
+  <view class="entity-selector-page">
+    <view class="header">
+      <view class="search-box">
+        <uni-icons type="search" size="22" color="#b8b8b8" />
+
+        <input
+          v-model="keyword"
+          class="search-input"
+          :placeholder="searchPlaceholder"
+          confirm-type="search"
+          @input="handleSearch"
+        />
+      </view>
+
+      <button class="add-btn" @click="openAddDialog">新增</button>
+    </view>
+
+    <view class="list-wrapper">
+      <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" />
+        </view>
+
+        <view class="item-content">
+          <text class="item-name">{{ item.pharmacyName }}</text>
+          <text v-if="item.address" class="item-address">
+            {{ item.address }}
+          </text>
+        </view>
+      </view>
+
+      <uni-load-more v-if="loading" status="loading" />
+
+      <uni-load-more v-else-if="finished && list.length > 0" status="noMore" />
+
+      <view v-if="!loading && list.length === 0" class="empty"> 暂无数据 </view>
+    </view>
+
+    <wd-popup
+      v-model="showAddDialog"
+      position="center"
+      root-portal
+      round
+      lock-scroll
+      :close-on-click-modal="false"
+      custom-style="width: 656rpx; overflow: hidden; background: #fff; border-radius: 24rpx;"
+      @close="resetAddForm"
+    >
+      <view class="add-dialog">
+        <view class="add-dialog__body">
+          <view class="add-dialog__title">{{ addTitle }}</view>
+
+          <view
+            class="add-dialog__input-wrapper"
+            :class="{ 'add-dialog__input-wrapper--error': Boolean(addError) }"
+          >
+            <input
+              v-model="addName"
+              class="add-dialog__input"
+              :placeholder="addPlaceholder"
+              :focus="showAddDialog"
+              maxlength="100"
+              confirm-type="done"
+              @input="clearAddError"
+              @confirm="confirmAdd"
+            />
+          </view>
+
+          <text v-if="addError" class="add-dialog__error">
+            {{ addError }}
+          </text>
+        </view>
+
+        <view class="add-dialog__actions">
+          <view
+            class="add-dialog__action add-dialog__action--cancel"
+            hover-class="add-dialog__action--hover"
+            @click="closeAddDialog"
+          >
+            取消
+          </view>
+
+          <view
+            class="add-dialog__action add-dialog__action--confirm"
+            hover-class="add-dialog__action--hover"
+            @click="confirmAdd"
+          >
+            确认
+          </view>
+        </view>
+      </view>
+    </wd-popup>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { computed, getCurrentInstance, reactive, ref } from 'vue'
+
+import { onLoad, onPullDownRefresh, onReachBottom } from '@dcloudio/uni-app'
+
+import { debounce } from '@/plugins/debounce'
+
+import { listWmDaPharmacyByNameApi } from '@/services/modules/task/entitySelector'
+import type {
+  ListWmDaPharmacyByNameRequest,
+  PharmacyItem,
+} from '@/services/modules/task/entitySelector/type'
+
+const aliasConfig = {
+  pharmacyName: {
+    entityName: '药店',
+  },
+} as const
+
+type PageAlias = keyof typeof aliasConfig
+
+interface PageQuery {
+  alias?: string
+}
+
+const pageAlias = ref<PageAlias>('pharmacyName')
+const keyword = ref('')
+const list = ref<PharmacyItem[]>([])
+const selected = ref<PharmacyItem>()
+const loading = ref(false)
+const finished = ref(false)
+
+const pagination = reactive({
+  current: 1,
+  size: 20,
+})
+
+const showAddDialog = ref(false)
+const addName = ref('')
+const addError = ref('')
+
+let requestVersion = 0
+
+const entityName = computed(() => aliasConfig[pageAlias.value].entityName)
+const searchPlaceholder = computed(() => `搜索${entityName.value}名称`)
+const addTitle = computed(() => `新增${entityName.value}`)
+const addPlaceholder = computed(() => `请输入${entityName.value}名称`)
+
+const loadList = async (reset = false) => {
+  if (!reset && (loading.value || finished.value)) {
+    return
+  }
+
+  if (reset) {
+    requestVersion += 1
+    pagination.current = 1
+    list.value = []
+    finished.value = false
+  }
+
+  const version = requestVersion
+  const currentPage = pagination.current
+
+  loading.value = true
+
+  try {
+    const params: ListWmDaPharmacyByNameRequest = {
+      current: currentPage,
+      size: pagination.size,
+      name: keyword.value.trim(),
+    }
+
+    const { data } = await listWmDaPharmacyByNameApi(params)
+
+    if (version !== requestVersion) {
+      return
+    }
+
+    const records = data.records ?? []
+
+    list.value = reset ? records : [...list.value, ...records]
+
+    finished.value = currentPage >= data.pages || records.length < pagination.size
+
+    if (!finished.value) {
+      pagination.current = currentPage + 1
+    }
+  } catch {
+    if (version === requestVersion) {
+      uni.showToast({
+        title: '列表加载失败,请稍后重试',
+        icon: 'none',
+      })
+    }
+  } finally {
+    if (version === requestVersion) {
+      loading.value = false
+    }
+  }
+}
+
+const handleSearch = debounce(
+  () => {
+    void loadList(true)
+  },
+  {
+    wait: 500,
+    leading: false,
+    trailing: true,
+  }
+)
+
+interface EventChannelLike {
+  emit: (eventName: string, payload?: unknown) => void
+}
+
+interface PageProxyWithEventChannel {
+  getOpenerEventChannel?: () => EventChannelLike | undefined
+}
+const pageInstance = getCurrentInstance()
+
+const getOpenerEventChannel = () => {
+  const proxy = pageInstance?.proxy as PageProxyWithEventChannel | null
+
+  return proxy?.getOpenerEventChannel?.()
+}
+
+const selectItem = (item: PharmacyItem) => {
+  const eventChannel = getOpenerEventChannel()
+  selected.value = item
+
+  eventChannel?.emit('pharmacyNameSelect', item)
+  uni.navigateBack()
+}
+
+const openAddDialog = () => {
+  addName.value = ''
+  addError.value = ''
+  showAddDialog.value = true
+}
+
+const closeAddDialog = () => {
+  showAddDialog.value = false
+}
+
+const resetAddForm = () => {
+  addName.value = ''
+  addError.value = ''
+}
+
+const clearAddError = () => {
+  if (addError.value) {
+    addError.value = ''
+  }
+}
+
+const confirmAdd = () => {
+  const name = addName.value.trim()
+
+  if (!name) {
+    addError.value = `${entityName.value}名称不能为空`
+    return
+  }
+
+  uni.$emit('entity-add', {
+    alias: pageAlias.value,
+    name,
+  })
+
+  showAddDialog.value = false
+}
+
+onLoad((query?: PageQuery) => {
+  if (query?.alias === 'pharmacyName') {
+    pageAlias.value = query.alias
+  }
+
+  void loadList(true)
+})
+
+onReachBottom(() => {
+  void loadList()
+})
+
+onPullDownRefresh(async () => {
+  try {
+    await loadList(true)
+  } finally {
+    uni.stopPullDownRefresh()
+  }
+})
+</script>
+
+<style lang="scss" scoped>
+.entity-selector-page {
+  min-height: 100vh;
+  background: #fff;
+}
+
+.header {
+  position: fixed;
+  top: 0;
+  right: 0;
+  left: 0;
+  z-index: 100;
+  display: flex;
+  align-items: center;
+  gap: 24rpx;
+  height: 120rpx;
+  padding: 20rpx 32rpx;
+  box-sizing: border-box;
+  background: #fff;
+  border-bottom: 1rpx solid #f2f3f5;
+}
+
+.search-box {
+  display: flex;
+  flex: 1;
+  align-items: center;
+  min-width: 0;
+  height: 72rpx;
+  padding: 0 24rpx;
+  box-sizing: border-box;
+  background: #f5f6f7;
+  border-radius: 36rpx;
+}
+
+.search-input {
+  flex: 1;
+  min-width: 0;
+  height: 72rpx;
+  margin-left: 16rpx;
+  font-size: 30rpx;
+  color: #333;
+}
+
+.add-btn {
+  flex-shrink: 0;
+  width: 152rpx;
+  height: 72rpx;
+  margin: 0;
+  padding: 0;
+  line-height: 72rpx;
+  font-size: 30rpx;
+  font-weight: 500;
+  color: #fff;
+  background: #3c9cff;
+  border-radius: 36rpx;
+
+  &::after {
+    border: 0;
+  }
+}
+
+.list-wrapper {
+  padding-top: 120rpx;
+  padding-bottom: env(safe-area-inset-bottom);
+}
+
+.list-item {
+  display: flex;
+  align-items: center;
+  min-height: 112rpx;
+  padding: 24rpx 32rpx;
+  box-sizing: border-box;
+  background: #fff;
+  border-bottom: 1rpx solid #f2f3f5;
+}
+
+.radio {
+  display: flex;
+  flex-shrink: 0;
+  align-items: center;
+  justify-content: center;
+  width: 38rpx;
+  height: 38rpx;
+  margin-right: 24rpx;
+  box-sizing: border-box;
+  border: 2rpx solid #d5d7da;
+  border-radius: 50%;
+}
+
+.radio--active {
+  border-color: #3c9cff;
+}
+
+.radio__dot {
+  width: 20rpx;
+  height: 20rpx;
+  background: #3c9cff;
+  border-radius: 50%;
+}
+
+.item-content {
+  flex: 1;
+  min-width: 0;
+}
+
+.item-name,
+.item-address {
+  display: block;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+.item-name {
+  font-size: 32rpx;
+  line-height: 44rpx;
+  color: #333;
+}
+
+.item-address {
+  margin-top: 8rpx;
+  font-size: 26rpx;
+  line-height: 38rpx;
+  color: #999;
+}
+
+.empty {
+  padding: 120rpx 32rpx;
+  font-size: 28rpx;
+  text-align: center;
+  color: #999;
+}
+
+.add-dialog {
+  width: 100%;
+  overflow: hidden;
+  background: #fff;
+}
+
+.add-dialog__body {
+  padding: 42rpx 32rpx 32rpx;
+}
+
+.add-dialog__title {
+  margin-bottom: 32rpx;
+  font-size: 36rpx;
+  font-weight: 500;
+  line-height: 50rpx;
+  text-align: center;
+  color: #333;
+}
+
+.add-dialog__input-wrapper {
+  height: 82rpx;
+  padding: 0 22rpx;
+  box-sizing: border-box;
+  border: 2rpx solid #dcdfe6;
+  border-radius: 10rpx;
+  transition: border-color 0.2s;
+}
+
+.add-dialog__input-wrapper--error {
+  border-color: #ee0a24;
+}
+
+.add-dialog__input {
+  width: 100%;
+  height: 78rpx;
+  font-size: 30rpx;
+  color: #333;
+}
+
+.add-dialog__error {
+  display: block;
+  margin-top: 12rpx;
+  font-size: 24rpx;
+  line-height: 34rpx;
+  color: #ee0a24;
+}
+
+.add-dialog__actions {
+  display: flex;
+  height: 104rpx;
+  border-top: 1rpx solid #f0f0f0;
+}
+
+.add-dialog__action {
+  display: flex;
+  flex: 1;
+  align-items: center;
+  justify-content: center;
+  font-size: 34rpx;
+  line-height: 104rpx;
+}
+
+.add-dialog__action--cancel {
+  color: #666;
+  border-right: 1rpx solid #f0f0f0;
+}
+
+.add-dialog__action--confirm {
+  font-weight: 500;
+  color: #3c9cff;
+}
+
+.add-dialog__action--hover {
+  background: #f5f6f7;
+}
+</style>

+ 1 - 1
src/pages-mine/compliance-evaluation/index.vue

@@ -60,8 +60,8 @@ import { computed, ref } from 'vue'
 
 import { onLoad } from '@dcloudio/uni-app'
 
-import type { AbilityTestResult } from '@/services/modules/mine/complianceEvaluation'
 import { getQuizPltTestResultApi } from '@/services/modules/mine/complianceEvaluation'
+import type { AbilityTestResult } from '@/services/modules/mine/complianceEvaluation/type'
 
 interface PageQuery {
   fromHome?: string

+ 121 - 78
src/pages-task/task-form/components/Area.vue

@@ -2,59 +2,46 @@
   <view class="area-select">
     <wd-cell
       title-width="200rpx"
-      :placeholder="'请选择' + taskFieldConfig.taskFiledValue"
       :title="taskFieldConfig.taskFiledValue"
+      :placeholder="`请选择${taskFieldConfig.taskFiledValue}`"
       :required="taskFieldConfig.isMustfill === '1'"
-      :value="cellValue"
-      :is-link="!isDisabled"
+      :value="displayLabel"
+      :is-link="!disabled"
       @click="handleOpen"
     />
 
     <wd-cascader
       v-model="cascaderValue"
-      v-model:visible="cascaderShow"
-      :title="'请选择' + taskFieldConfig.taskFiledValue"
-      :options="areaOptions"
+      v-model:visible="visible"
+      :title="`请选择${taskFieldConfig.taskFiledValue}`"
+      :options="options"
       @confirm="handleConfirm"
     />
   </view>
 </template>
 
 <script setup lang="ts">
-import { computed, ref } from 'vue'
+import { computed, nextTick, ref } from 'vue'
 
 import { useCascaderAreaData } from '@vant/area-data'
 
 import type { TaskFieldConfigItem } from '@/services/modules/task/taskFrom/type'
 
-type FieldValue = string | number | undefined
-type FieldLabel = string | undefined
-type AreaSelectLevel = 2 | 3
+type AreaLevel = 2 | 3
+
+type FieldValue = string | undefined
 
 interface AreaOption {
-  value: string | number
+  value: string
   text: string
   children?: AreaOption[]
-  disabled?: boolean
-  tip?: string
   isLeaf?: boolean
 }
 
-interface CascaderConfirmEvent {
-  value: FieldValue | FieldValue[]
-  selectedItems?: AreaOption[]
-  selectedOptions?: AreaOption[]
-}
-
 interface Props {
   taskFieldConfig: TaskFieldConfigItem
   disabled?: boolean
-
-  /**
-   * 2:只选择省市
-   * 3:选择省市区
-   */
-  selectLevel?: AreaSelectLevel
+  selectLevel?: AreaLevel
 }
 
 const props = withDefaults(defineProps<Props>(), {
@@ -62,92 +49,148 @@ const props = withDefaults(defineProps<Props>(), {
   selectLevel: 3,
 })
 
-const label = defineModel<FieldLabel>('label')
+/**
+ * value / label 都保存路径
+ *
+ * 三级:
+ * 北京市-北京市城区-东城区
+ *
+ * 二级:
+ * 北京市-北京市城区
+ */
 const value = defineModel<FieldValue>('value')
 
-const cascaderShow = ref(false)
-const cascaderValue = ref<FieldValue>()
+const label = defineModel<string>('label')
 
-const SELECTED_LABEL_SEPARATOR = '-'
+const visible = ref(false)
 
-const isDisabled = computed(() => props.disabled)
+/**
+ * cascader 内部使用 code
+ */
+const cascaderValue = ref<string | number | undefined>()
 
-const rawAreaOptions = useCascaderAreaData() as AreaOption[]
+const rawOptions = useCascaderAreaData() as AreaOption[]
 
-const areaOptions = computed<AreaOption[]>(() => {
+const options = computed(() => {
   if (props.selectLevel === 2) {
-    return toProvinceCityOptions(rawAreaOptions)
+    return convertCityLeaf(rawOptions)
   }
 
-  return rawAreaOptions
+  return rawOptions
 })
 
-const cellValue = computed(() => {
-  if (label.value) return label.value
-
-  const selectedPath = findOptionPath(areaOptions.value, value.value)
-  return formatSelectedOptions(selectedPath)
+const displayLabel = computed(() => {
+  return label.value || value.value || ''
 })
 
-const handleOpen = () => {
-  if (isDisabled.value) return
+/**
+ * 打开
+ */
+const handleOpen = async () => {
+  if (props.disabled) return
+
+  /**
+   * 根据保存的路径反查code
+   */
+  cascaderValue.value = findValueByPath(options.value, value.value)
+
+  await nextTick()
 
-  cascaderValue.value = value.value
-  cascaderShow.value = true
+  visible.value = true
 }
 
-const handleConfirm = (event: CascaderConfirmEvent) => {
-  const selectedItems = event.selectedItems ?? event.selectedOptions ?? []
-  const lastSelectedOption = selectedItems[selectedItems.length - 1]
+/**
+ * 选择确认
+ */
+const handleConfirm = (event: { selectedItems?: AreaOption[] }) => {
+  const items = event.selectedItems ?? []
+
+  if (!items.length) return
 
-  if (!lastSelectedOption) return
+  const path = formatPath(items)
 
-  value.value = lastSelectedOption.value
-  label.value = formatSelectedOptions(selectedItems)
-  cascaderValue.value = lastSelectedOption.value
+  /**
+   * 保存路径
+   */
+  value.value = path
+
+  label.value = path
+
+  /**
+   * cascader保持code
+   */
+  cascaderValue.value = items[items.length - 1].value
 }
 
-const toProvinceCityOptions = (options: AreaOption[]): AreaOption[] => {
-  return options.map((province) => ({
-    ...province,
-    children: province.children?.map(toCityLeafOption),
+/**
+ * 省市二级
+ */
+const convertCityLeaf = (list: AreaOption[]): AreaOption[] => {
+  return list.map((item) => ({
+    ...item,
+    children: item.children?.map((city) => ({
+      value: city.value,
+      text: city.text,
+      isLeaf: true,
+    })),
   }))
 }
 
-const toCityLeafOption = (city: AreaOption): AreaOption => {
-  return {
-    value: city.value,
-    text: city.text,
-    disabled: city.disabled,
-    tip: city.tip,
-    isLeaf: true,
-  }
-}
+/**
+ * 根据路径查找最后一级code
+ *
+ * value:
+ * 广东省-广州市-天河区
+ *
+ * 返回:
+ * 440106
+ */
+const findValueByPath = (list: AreaOption[], path?: string): string | undefined => {
+  if (!path) return undefined
+
+  const target = path.split('-')
+
+  const result = searchPath(list, target, 0)
 
-const formatSelectedOptions = (options: AreaOption[]) => {
-  return options
-    .map((item) => item.text)
-    .filter(Boolean)
-    .join(SELECTED_LABEL_SEPARATOR)
+  return result?.value
 }
 
-const findOptionPath = (options: AreaOption[], targetValue: FieldValue): AreaOption[] => {
-  if (targetValue === undefined || targetValue === '') return []
+/**
+ * DFS匹配路径
+ */
+const searchPath = (
+  list: AreaOption[],
+  target: string[],
+  index: number
+): AreaOption | undefined => {
+  for (const item of list) {
+    if (item.text !== target[index]) {
+      continue
+    }
 
-  for (const option of options) {
-    if (option.value === targetValue) {
-      return [option]
+    /**
+     * 最后一层
+     */
+    if (index === target.length - 1) {
+      return item
     }
 
-    if (option.children?.length) {
-      const childPath = findOptionPath(option.children, targetValue)
+    if (item.children?.length) {
+      const result = searchPath(item.children, target, index + 1)
 
-      if (childPath.length) {
-        return [option, ...childPath]
+      if (result) {
+        return result
       }
     }
   }
 
-  return []
+  return undefined
+}
+
+/**
+ * 拼接路径
+ */
+const formatPath = (items: AreaOption[]) => {
+  return items.map((item) => item.text).join('-')
 }
 </script>

+ 22 - 3
src/pages-task/task-form/components/SingleSelect.vue

@@ -102,23 +102,42 @@ const cellValue = computed(() => {
 })
 
 /**
- * 同步外部表单值和 picker 当前选中值。
+ * 同步外部 value
+ *
+ * 1. value 存在:
+ *    - 同步 pickerValue
+ *    - 根据 options 自动补充 label
+ *
+ * 2. value 清空:
+ *    - 清空 pickerValue
+ *    - 清空 label
  */
 watch(
   value,
   (currentValue) => {
     if (currentValue === undefined || currentValue === '') {
       pickerValue.value = []
+      label.value = ''
       return
     }
 
-    pickerValue.value = [String(currentValue)]
+    const valueString = String(currentValue)
+
+    pickerValue.value = [valueString]
+
+    /**
+     * value 回显时自动匹配 label
+     */
+    const selectedOption = pickerOptions.value.find((item) => String(item.value) === valueString)
+
+    if (selectedOption && label.value !== selectedOption.label) {
+      label.value = selectedOption.label
+    }
   },
   {
     immediate: true,
   }
 )
-
 /**
  * 比较新旧字段值。
  *

+ 41 - 3
src/pages-task/task-form/composables/useTaskSelectHandlers.ts

@@ -1,5 +1,6 @@
 import type { Ref } from 'vue'
 
+import type { PharmacyItem } from '@/services/modules/task/entitySelector/type'
 import { getListDrugTableApi } from '@/services/modules/task/taskFrom/index'
 
 import type {
@@ -163,10 +164,23 @@ export const useTaskSelectHandlers = ({
    * 特殊接口请求和业务校验写在这里。
    */
   const handleSingleSelectBeforeOpen = async (field: TaskFieldConfigViewItem): Promise<boolean> => {
-    /**
-     * OTC 推广任务示例。
-     */
+    console.log('field', field)
+
+    if (field.taskTypeId === '18' && field.alias === 'pharmacyName') {
+      uni.navigateTo({
+        url: `/pages-common/entity-selector/index?alias=pharmacyName`,
+        events: {
+          pharmacyNameSelect: (selectedPharmacyItem: PharmacyItem) => {
+            setPharmacyNameSelectEvent(selectedPharmacyItem)
+          },
+        },
+      })
+      return false
+    }
     if (taskTypeId.value === '47') {
+      /**
+       * OTC 推广任务示例。
+       */
       const scorePackageValue = getFieldFormValueByAlias('scorePackage')
       console.log('scorePackageValue', scorePackageValue)
       if (field.taskFiledValue === '产品') {
@@ -282,6 +296,30 @@ export const useTaskSelectHandlers = ({
     return true
   }
 
+  const setPharmacyNameSelectEvent = (selectedPharmacyItem: PharmacyItem) => {
+    console.log('setPharmacyNameSelectEvent', selectedPharmacyItem)
+
+    setFieldFormValueByAlias('pharmacyName', {
+      label: selectedPharmacyItem.pharmacyName,
+      value: selectedPharmacyItem.pharmacyName,
+    })
+    setFieldFormValueByAlias('pharmacyType', {
+      label: undefined,
+      value: selectedPharmacyItem.pharmacyType,
+    })
+    setFieldFormValueByAlias('address', {
+      label: selectedPharmacyItem.address,
+      value: selectedPharmacyItem.address,
+    })
+
+    const address = `${selectedPharmacyItem.province}-${selectedPharmacyItem.city}-${selectedPharmacyItem.area}`
+    setFieldFormValueByAlias('shengshiqu', {
+      label: address,
+
+      value: address,
+    })
+  }
+
   return {
     handleSingleSelectBeforeOpen,
     handleSingleSelectChange,

+ 9 - 0
src/pages.json

@@ -81,6 +81,15 @@
             "navigationBarTitleText": "位置选择",
             "navigationStyle": "default"
           }
+        },
+        {
+          "path": "entity-selector/index",
+          "style": {
+            "navigationBarTitleText": "实体选择",
+            "navigationStyle": "default",
+            "enablePullDownRefresh": true,
+            "onReachBottomDistance": 80
+          }
         }
       ]
     },

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

@@ -0,0 +1,13 @@
+import http from '../../../index'
+import type { ListWmDaPharmacyByNameRequest, ListWmDaPharmacyByNameResponse } from './type'
+
+export const listWmDaPharmacyByNameApi = (params: ListWmDaPharmacyByNameRequest) => {
+  return http.get<ListWmDaPharmacyByNameResponse>(
+    `/admin/wmdapharmacy/listWmDaPharmacyByName?`,
+    params,
+    {
+      loading: true,
+      loadingText: '加载中...',
+    }
+  )
+}

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

@@ -0,0 +1,114 @@
+export interface ListWmDaPharmacyByNameRequest {
+  current: number
+  size: number
+  name: string
+}
+
+export interface ListWmDaPharmacyByNameResponse {
+  current: number
+  hitCount: boolean
+  optimizeCountSql: boolean
+  orders: unknown[]
+  pages: number
+  records: PharmacyItem[]
+  searchCount: boolean
+  size: number
+  total: number
+}
+
+export interface PharmacyItem {
+  /**
+   * 主键 ID
+   */
+  id: string
+
+  /**
+   * 药店名称
+   */
+  pharmacyName: string
+
+  /**
+   * 药店类型
+   */
+  pharmacyType: string
+
+  /**
+   * 省
+   */
+  province: string
+
+  /**
+   * 市
+   */
+  city: string
+
+  /**
+   * 区
+   */
+  area: string
+
+  /**
+   * 详细地址
+   */
+  address: string
+
+  /**
+   * 纬度
+   */
+  latitude: string
+
+  /**
+   * 经度
+   */
+  longitude: string
+
+  /**
+   * 备注
+   */
+  remark: string
+
+  /**
+   * 租户 ID
+   */
+  tenantId: number
+
+  /**
+   * 数据清洗标识
+   */
+  dataCleaning: boolean
+
+  /**
+   * 删除标识
+   */
+  delFlag: string
+
+  /**
+   * 启用标识
+   */
+  enableFlag: string
+
+  /**
+   * 部门 ID
+   */
+  deptId: string | null
+
+  /**
+   * 创建时间
+   */
+  createTime: string | null
+
+  /**
+   * 创建人
+   */
+  createUser: string | null
+
+  /**
+   * 更新时间
+   */
+  updateTime: string | null
+
+  /**
+   * 更新人
+   */
+  updateUser: string | null
+}