Procházet zdrojové kódy

整改基本完成

Huanyi před 1 týdnem
rodič
revize
f94af513c7

+ 1 - 0
src/api/archieves/customer/types.ts

@@ -64,6 +64,7 @@ export interface CustomerOnOrderVO {
 export interface CustomerOnOrderQuery extends PageQuery {
   content?: string;
   tenantId?: string | number;
+  stationId?: number;
 }
 
 /**

+ 2 - 0
src/api/system/store/types.ts

@@ -257,6 +257,8 @@ export interface StoreOrderVO {
   id: number;
   name: string;
   services: number[];
+  site: number;
+  tenantId: string;
 }
 
 export interface StoreDispatchVO {

+ 9 - 3
src/components/PageSelect/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="page-select">
-    <el-select v-bind="{ ...$attrs, value: undefined }" v-model="localValue" :filterable="true" :remote="false"
-      @visible-change="handleVisibleChange" @change="handleInput">
+    <el-select v-bind="{ ...$attrs, value: undefined }" v-model="localValue" :filterable="true" :remote="true"
+      :remote-method="onFilterMethod" @visible-change="handleVisibleChange" @change="handleInput">
       <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
       <!-- 分页组件 -->
       <div v-if="total > 0" class="brand-pagination">
@@ -48,7 +48,7 @@ const props = defineProps({
   }
 });
 
-const emit = defineEmits(['update:modelValue', 'page-change', 'visible-change']);
+const emit = defineEmits(['update:modelValue', 'page-change', 'visible-change', 'filter-method']);
 
 const localValue = ref(props.modelValue);
 const currentPage = ref(1);
@@ -107,6 +107,12 @@ const handlePageChange = (page: number) => {
   currentPage.value = page;
   emit('page-change', page);
 };
+
+// 处理筛选输入变化,重置到第1页
+const onFilterMethod = (query: string) => {
+  currentPage.value = 1;
+  emit('filter-method', query);
+};
 </script>
 
 <style scoped>

+ 22 - 0
src/views/fulfiller/pool/index.vue

@@ -96,6 +96,15 @@
           </template>
         </el-table-column>
 
+        <el-table-column label="服务类型" width="150">
+          <template #default="scope">
+            <el-tag v-for="st in getServiceTypeList(scope.row.serviceTypes)" :key="st" size="small" type="warning"
+              effect="light" style="margin-right:4px;margin-bottom:4px;">
+              {{ st }}
+            </el-tag>
+          </template>
+        </el-table-column>
+
         <el-table-column label="技能标签" min-width="180">
           <template #default="scope">
             <el-tag v-for="tag in scope.row.tags" :key="tag.id" :type="tag.colorType" size="small" class="skill-tag"
@@ -201,6 +210,12 @@
               <el-tag size="small" type="warning" effect="plain" v-if="currentItem.workType === 'full_time'"
                 style="margin-left:5px">全职专送</el-tag>
             </div>
+            <div class="tags-row" style="margin-top:8px;">
+              <el-tag v-for="st in getServiceTypeList(currentItem.serviceTypes)" :key="st" size="small" type="warning"
+                effect="light" style="margin-right:6px;">
+                {{ st }}
+              </el-tag>
+            </div>
           </div>
         </div>
 
@@ -909,6 +924,13 @@ const getServiceName = (serviceId: number | string) => {
   return item ? item.name : '未知服务'
 }
 
+/** 获取服务类型名称列表(从逗号分隔字符串解析) @Author: Antigravity */
+const getServiceTypeList = (serviceTypes: string | undefined): string[] => {
+  if (!serviceTypes) return []
+  const ids = serviceTypes.split(',').filter(Boolean)
+  return ids.map(id => getServiceName(id))
+}
+
 const getSubOrderStatusName = (status: number) => {
   const map: Record<number, string> = { 0: '待派单', 1: '待接单', 2: '待服务', 3: '服务中', 4: '已完成', 5: '已取消' }
   return map[status] || '未知'

+ 37 - 3
src/views/order/orderList/index.vue

@@ -14,6 +14,9 @@
             </el-radio-group>
             <el-input v-model="filters.content" placeholder="订单号/品牌/宠主/手机号" class="search-input" prefix-icon="Search"
               clearable @clear="handleSearch" @keyup.enter="handleSearch" />
+            <el-cascader v-model="filterCascaderValue" :options="areaTreeOptions"
+              :props="{ checkStrictly: true, value: 'id', label: 'name' }" placeholder="所属站点" clearable
+              style="width: 350px; margin-left: 10px;" @change="handleFilterCascaderChange" />
             <el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
             <el-button type="success" icon="Download" @click="handleExport"
               v-hasPermi="['order:orderList:export']">导出Excel</el-button>
@@ -224,7 +227,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, reactive, onMounted, onUnmounted, nextTick, getCurrentInstance } from 'vue';
+import { ref, reactive, computed, onMounted, onUnmounted, nextTick, getCurrentInstance } from 'vue';
 import { useRouter, useRoute } from 'vue-router';
 import { ElMessage, ElMessageBox } from 'element-plus';
 import fulfillerEnums from '@/json/fulfiller.json';
@@ -259,7 +262,8 @@ const loading = ref(false);
 const filters = reactive({
   service: '',
   status: '',
-  content: ''
+  content: '',
+  site: undefined as number | undefined
 });
 
 const pagination = reactive({
@@ -272,6 +276,20 @@ const tableData = ref([]);
 const serviceOptions = ref([]);
 const areaStationList = ref([]);
 const areaStationMap = ref({});
+const areaTreeOptions = computed(() => {
+  const buildTree = (data: any[], parentId: any): any[] => {
+    return data
+      .filter(item => String(item.parentId) === String(parentId))
+      .map(item => {
+        const children = buildTree(data, item.id);
+        const res: any = { id: item.id, name: item.name };
+        if (children && children.length > 0) res.children = children;
+        return res;
+      });
+  };
+  return buildTree(areaStationList.value, 0);
+});
+const filterCascaderValue = ref<any[]>([]);
 const storeMap = ref({});
 
 onMounted(() => {
@@ -343,6 +361,21 @@ const handleStatusTabChange = async () => {
   handleSearch();
 };
 
+const handleFilterCascaderChange = (val: any[]) => {
+  if (val && val.length > 0) {
+    const lastId = val[val.length - 1];
+    const node = areaStationList.value.find((item: any) => item.id === lastId);
+    if (node && node.type === 2) {
+      filters.site = lastId;
+    } else {
+      filters.site = undefined;
+    }
+  } else {
+    filters.site = undefined;
+  }
+  handleSearch();
+};
+
 const handleSearch = (isPolling: any = false) => {
   const isAutoPoll = isPolling === true;
   if (!isAutoPoll) {
@@ -353,7 +386,8 @@ const handleSearch = (isPolling: any = false) => {
     pageSize: pagination.size,
     service: filters.service !== '' ? filters.service : undefined,
     status: filters.status !== '' ? Number(filters.status) : undefined,
-    content: filters.content || undefined
+    content: filters.content || undefined,
+    site: filters.site || undefined
   })
     .then((res) => {
       tableData.value = res.rows || [];

+ 21 - 5
src/views/order/purchase/index.vue

@@ -23,7 +23,8 @@
                     </template>
                     <PageSelect v-model="form.merchantId" placeholder="请选择商户门店" size="large" style="width: 100%"
                       :options="merchantOptions" :total="storeTotal" :page-size="5" @page-change="handleStorePageChange"
-                      @update:modelValue="handleStoreChange" />
+                      @update:modelValue="handleStoreChange" @filter-method="handleStoreFilter"
+                      @visible-change="handleStoreVisible" />
                   </el-form-item>
                 </el-col>
                 <el-col :span="12">
@@ -53,7 +54,7 @@
                     @click="form.petId = p.id">
                     <el-avatar :size="48" :src="p.avatarUrl || p.avatar" shape="square" style="border-radius: 6px;">{{
                       p.name.charAt(0)
-                      }}</el-avatar>
+                    }}</el-avatar>
                     <div class="pet-info">
                       <div class="name">{{ p.name }}</div>
                       <div class="sub">{{ p.breed }}</div>
@@ -222,7 +223,7 @@ import { createOrder } from '@/api/order/order'
 // --- State ---
 const userOptions = ref([])
 const userTotal = ref(0)
-const userQuery = reactive({ pageNum: 1, pageSize: 5, content: '', tenantId: undefined })
+const userQuery = reactive({ pageNum: 1, pageSize: 5, content: '', tenantId: undefined, stationId: undefined })
 const userLoading = ref(false)
 
 const serviceList = [
@@ -244,7 +245,7 @@ const currentPets = ref([])
 const stores = ref([])
 const storeTotal = ref(0)
 const allServices = ref([])
-const storeQuery = reactive({ pageNum: 1, pageSize: 5 })
+const storeQuery = reactive({ pageNum: 1, pageSize: 5, name: '' })
 
 const form = reactive({
   merchantId: '',
@@ -335,6 +336,20 @@ const handleStorePageChange = (page) => {
   fetchStores()
 }
 
+const handleStoreFilter = (query) => {
+  storeQuery.name = query || ''
+  storeQuery.pageNum = 1
+  fetchStores()
+}
+
+const handleStoreVisible = (visible) => {
+  if (visible) {
+    storeQuery.name = ''
+    storeQuery.pageNum = 1
+    fetchStores()
+  }
+}
+
 const handleStoreChange = (val) => {
   // 切换门店时强制清空已选客户和宠物
   form.userId = ''
@@ -511,9 +526,10 @@ const fetchUsers = () => {
   if (!form.merchantId) return
   userLoading.value = true
 
-  // 关联当前选中门店的租户ID
+  // 关联当前选中门店的租户ID和站点ID
   const store = stores.value.find(s => s.id === form.merchantId)
   userQuery.tenantId = store ? store.tenantId : undefined
+  userQuery.stationId = store ? store.site : undefined
 
   listCustomerOnOrder(userQuery).then(res => {
     userOptions.value = res.rows || []

+ 1 - 1
src/views/system/store/index.vue

@@ -896,7 +896,7 @@ watch(addressCascaderValue, (newValue) => {
 
 const getServiceName = (serviceId: number): string => {
   const service = serviceList.value.find(item => item.id === serviceId);
-  return service ? service.name : String(serviceId);
+  return service ? service.name : '未知服务';
 };
 
 const getStatusList = async () => {