Просмотр исходного кода

feat: 联调template management页面相关接口

Jack Zhou 1 месяц назад
Родитель
Сommit
c3a7c55978

+ 47 - 1
src/api/module/report.ts

@@ -7,7 +7,7 @@ const baseUrl = `${base}/main_new_version.php`
  * 获取report template management表格列数据
  */
 export const getReportTemplateManagementTable = (params: any, config: any) => {
-  return HttpAxios.get(
+  return HttpAxios.post(
     `${baseUrl}`,
     {
       action: 'report_config',
@@ -18,6 +18,21 @@ export const getReportTemplateManagementTable = (params: any, config: any) => {
   )
 }
 
+/**
+ * 更改Report Template Management表格 Is Active状态
+ */
+export const changeReportTemplateIsActive = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'report_config',
+      operate: 'active',
+      ...params
+    },
+    config
+  )
+}
+
 /**
  * 获取Report Fields Configuration 列表数据
  */
@@ -64,4 +79,35 @@ export const getSpecificRolesGroupName = (params: any, config: any) => {
     },
     config
   )
+}
+
+
+/**
+ * 保存 Create New Report Template页面数据
+ */
+export const saveNewReportTemplate = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'report_config',
+      operate: 'save',
+      ...params
+    },
+    config
+  )
+}
+
+/**
+ * 编辑report template
+ */
+export const editReportTemplate = (params: any, config: any) => {
+  return HttpAxios.post(
+    `${baseUrl}`,
+    {
+      action: 'report_config',
+      operate: 'add',
+      ...params
+    },
+    config
+  )
 }

+ 19 - 1
src/components/VTag/src/VTag.vue

@@ -13,6 +13,8 @@ interface internalProps {
     | 'Pending Approval'
     | 'Approved'
     | 'Rejected'
+    | 'Active'
+    | 'Inactive'
   large?: boolean
 }
 
@@ -28,7 +30,9 @@ const mappingTable = new Map([
   ['Arrived', 'arrived'],
   ['Completed', 'completed'],
   ['Departed', 'Departed'],
-  ['Pending Approval', 'pending-approval']
+  ['Pending Approval', 'pending-approval'],
+  ['Active', 'active'],
+  ['Inactive', 'inactive']
 ])
 defineProps<internalProps>()
 </script>
@@ -135,6 +139,20 @@ defineProps<internalProps>()
       background-color: var(--color-tag-unfinished-approval);
     }
   }
+  &.v-tag__active {
+    background-color: var(--color-tag-completed-bg);
+    color: var(--color-tag-completed);
+    .dot {
+      background-color: var(--color-tag-completed);
+    }
+  }
+  &.v-tag__inactive {
+    background-color: var(--color-tag-cancelled-bg);
+    color: var(--color-tag-cancelled);
+    .dot {
+      background-color: var(--color-tag-cancelled);
+    }
+  }
   &.v-tag__approved {
     background-color: var(--color-tag-approved-bg);
     color: var(--color-tag-approved);

+ 0 - 1
src/stores/modules/breadCrumb.ts

@@ -21,7 +21,6 @@ const whiteList = [
   'Create New Booking',
   'Destination Create New Rule',
   "Create Report Template",
-  'Report Management'
 ]
 
 export const useBreadCrumb = defineStore('breadCrumb', {

+ 24 - 0
src/views/Report/src/components/ReportSchedule/src/ReportSchedule.vue

@@ -26,6 +26,30 @@ const handleSubmitRolling = (data: any) => {
   rollingStartDate.value = data.rollingStartDate
   rollingEndDate.value = data.rollingEndDate
 }
+interface data {
+  scheduleRuleValidityPeriod: {
+    type: 'permanent vaild' | 'custom period'
+    startDate: string
+    endDate: string
+  }
+  reportDataTimeRange: {
+    dateField: 'ETA' | 'ETD'
+    configurationMethod: 'Dynamic Rolling Range' | 'Fixed Range'
+    startDate: string
+    endDate: string
+  }
+  reportDeliveryFrequency: {
+    emailRecipients: string
+    timezone: string
+    deliveryFrequency: 'Daily' | 'Weekly' | 'Monthly' | 'Quarterly' | 'Yearly'
+    time: string
+  }
+  reportDataReview: {
+    searchData: []
+    tableColumns: []
+    sortOptions: []
+  }
+}
 </script>
 <template>
   <div class="Title">

+ 5 - 5
src/views/TemplateManagement/src/TemplateManagement.vue

@@ -26,12 +26,12 @@ const aiModelList = [
 
 const activeOptions = [
   {
-    label: 'Yes',
-    value: 't'
+    label: 'Active',
+    value: true
   },
   {
-    label: 'No',
-    value: 'f'
+    label: 'Inactive',
+    value: false
   }
 ]
 
@@ -49,7 +49,7 @@ const applicationScopeOptions = [
 const tableRef = ref()
 
 const Search = () => {
-  tableRef.value.SearchOperationLog(queryData.value)
+  tableRef.value.searchTableData(queryData.value)
 }
 
 const handleCreate = () => {

+ 146 - 66
src/views/TemplateManagement/src/components/CreateReportTemplate/src/CreateReportTemplate.vue

@@ -1,42 +1,63 @@
 <script lang="ts" setup>
-import { useRouter } from 'vue-router'
+import { useRouter, useRoute } from 'vue-router'
 import partyIDSelect from './components/partyIDSelect.vue'
 import GroupNameSelect from './components/GroupNameSelect.vue'
 import { VueDraggable } from 'vue-draggable-plus'
 import AdjustmentField from './components/AdjustmentField.vue'
 
 const router = useRouter()
-const filterRef: Ref<HTMLElement | null> = ref(null)
-const searchData = ref({
-  text_search: '',
-  request_date_start: '',
-  request_date_end: '',
-  ai_model: '',
-  response_duration_type: '',
-  response_duration_num: null
-})
+const route = useRoute()
 
 const infoData = ref({
   reportName: '',
   reportLevel: '',
   reportDescription: ''
 })
+const pageLoading = ref(false)
+onMounted(() => {
+  if (route.query.serial_no) {
+    pageLoading.value = true
+    $api
+      .editReportTemplate({ serial_no: route.query.serial_no })
+      .then((res) => {
+        console.log('editReportTemplate', res)
+        infoData.value = {
+          reportName: res.data.reportName,
+          reportLevel: res.data.reportLevel,
+          reportDescription: res.data.reportDescription
+        }
+        fieldsList.value = res.data.reportFields
+        accessControlType.value = res.data.reportAccess.type
+        specificRoles.value = {
+          partyId: res.data.reportAccess.partyId,
+          groupName: res.data.reportAccess.groupName
+        }
+      })
+      .finally(() => {
+        pageLoading.value = false
 
-const tableRef = ref()
-
-const Search = () => {
-  tableRef.value.SearchOperationLog(searchData.value)
-}
-
-const handleCreate = () => {
-  // Navigate to the Create Report Template page
-  router.push('/create-report-template')
-}
+        watch(accessControlType, (newVal) => {
+          if (newVal === 'Specific Roles') {
+            // 等待下一个渲染周期结束后,获取detailRef的高度
+            nextTick(() => {
+              if (detailRef.value) {
+                detailRef.value.scrollIntoView({
+                  behavior: 'smooth', // 平滑滚动
+                  block: 'start' // 滚动到顶部对齐
+                })
+              }
+            })
+          }
+        })
+      })
+  }
+})
 
 interface Field {
   field: string
   title: string
   displayName: string
+  fieldType: string
   value?: string
   isFilter: boolean
   isSort: boolean
@@ -64,6 +85,10 @@ const handleDeleteField = (field: string) => {
 const AdjustmentFieldRef = ref()
 // 打开定制表格弹窗
 const handleCustomizeColumns = () => {
+  if (!infoData.value.reportLevel) {
+    ElMessage.warning('Please select the report level.')
+    return
+  }
   const params = {
     serial_no: '',
     level: infoData.value.reportLevel
@@ -74,8 +99,6 @@ const handleCustomizeColumns = () => {
     'Drag item over to this selection or click "add" icon to show the field on report template list'
   )
 }
-// 定制表格
-const customizeColumns = async () => {}
 
 const newFieldInfo = ref<{
   name: string
@@ -95,60 +118,105 @@ const handleFieldTypeChange = () => {
   newFieldInfo.value.value = ''
 }
 const addNewField = () => {
-  if (newFieldInfo.value.name) {
-    fieldsList.value.push({
-      field: newFieldInfo.value.name,
-      title: newFieldInfo.value.name,
-      value: newFieldInfo.value.value,
-      displayName: '',
-      isFilter: false,
-      isSort: false
-    })
-    newFieldInfo.value = {
-      name: '',
-      fieldType: 'Blank',
-      value: ''
-    }
-    addNewFieldVisible.value = false
-  } else {
+  console.log(newFieldInfo.value.name?.trim(), 'newFieldInfo', newFieldInfo.value)
+  if (!newFieldInfo.value.name?.trim()) {
     ElMessage.warning('Please enter the new field name.')
     return
   }
+
+  if (newFieldInfo.value.fieldType === 'Fixed Value' && !newFieldInfo.value.value?.trim()) {
+    ElMessage.warning('Please enter the fixed value.')
+    return
+  }
+  fieldsList.value.unshift({
+    field: newFieldInfo.value.name,
+    title: newFieldInfo.value.name,
+    displayName: newFieldInfo.value.name,
+    value: newFieldInfo.value.value,
+    fieldType: 'Custom',
+    isFilter: false,
+    isSort: false
+  })
+  newFieldInfo.value = {
+    name: '',
+    fieldType: 'Blank',
+    value: ''
+  }
+  addNewFieldVisible.value = false
 }
 // 调整应用字段
 const handleApplay = (data: any) => {
   console.log('data', data)
+  const customizeData = fieldsList.value.filter((item: any) => item.field_type === 'Custom')
+  fieldsList.value = data.map((item: any) => {
+    return {
+      field: item.field,
+      title: item.label,
+      displayName: item.label,
+      fieldType: item.fieldType,
+      isFilter: false,
+      isSort: false,
+      fieldLevel: item.fieldLevel,
+      groupName: item.groupName,
+      ids: item.ids,
+      dataType: item.dataType
+    }
+  })
+  fieldsList.value = [...customizeData, ...fieldsList.value]
 }
 
-const reportAccessControlRadio = ref('All Users')
+const accessControlType = ref('All Users')
 const detailRef: Ref<HTMLElement | null> = ref(null)
-watch(reportAccessControlRadio, (newVal) => {
-  if (newVal === 'Specific Roles') {
-    // 等待下一个渲染周期结束后,获取detailRef的高度
-    nextTick(() => {
-      if (detailRef.value) {
-        detailRef.value.scrollIntoView({
-          behavior: 'smooth', // 平滑滚动
-          block: 'start' // 滚动到顶部对齐
-        })
-      }
-    })
-  }
+
+const specificRoles = ref({
+  partyId: [],
+  groupName: []
 })
+const changePartyId = (val: string[]) => {
+  specificRoles.value.partyId = val
+}
+const changeGroupName = (val: string[]) => {
+  specificRoles.value.groupName = val
+}
 
-const loading = ref(false)
+const fieldLoading = ref(false)
 const handleRightRemove = () => {}
+
+const handleCancel = () => {
+  router.push('/template-management')
+}
+
+const handleSave = () => {
+  const data = {
+    report_name: infoData.value.reportName,
+    report_level: infoData.value.reportLevel,
+    report_description: infoData.value.reportDescription,
+    access_type: accessControlType.value,
+    party_ids: specificRoles.value.partyId || [],
+    group_names: specificRoles.value.groupName || [],
+    fieldsList: fieldsList.value,
+    serial_no: route.query.serial_no || ''
+  }
+  console.log('Saved Data:', data)
+  $api.saveNewReportTemplate(data).then((res: any) => {
+    if (res.code === 200) {
+      ElMessage.success('Report Template saved successfully!')
+    } else {
+      ElMessage.error(res.message || 'Failed to save Report Template.')
+    }
+  })
+}
 </script>
 <template>
-  <div class="dashboard">
+  <div class="dashboard" v-vloading="pageLoading">
     <div class="Title">
       <span>Create New Report Template</span>
       <div class="button-group">
-        <el-button type="default" @click="handleCreate">
+        <el-button type="default" @click="handleCancel">
           <span class="font_family icon-icon_return_b" style="margin-right: 3px"></span
           >Cancel</el-button
         >
-        <el-button :disabled="true" class="el-button--main" @click="handleCreate">
+        <el-button class="el-button--main" @click="handleSave">
           <span class="font_family icon-icon_save_b" style="margin-right: 3px"></span
           >Save</el-button
         >
@@ -227,7 +295,7 @@ const handleRightRemove = () => {}
           </div>
           <div class="fields-list" v-else>
             <VueDraggable
-              v-vloading="loading"
+              v-vloading="fieldLoading"
               v-model="fieldsList"
               class="column-list"
               ghost-class="ghost-column"
@@ -243,10 +311,8 @@ const handleRightRemove = () => {}
                   style="margin-right: 12px; font-size: 16px"
                 ></span>
                 <div class="label">
-                  <span style="font-weight: 700">[{{ fieldItem.title }}]</span>
-                  <span style="margin-left: 8px">{{
-                    fieldItem.displayName || fieldItem.title
-                  }}</span>
+                  <span style="font-weight: 700">[{{ fieldItem.field }}]</span>
+                  <span style="margin-left: 8px">{{ fieldItem.title }}</span>
                 </div>
                 <el-input
                   class="display-name"
@@ -255,8 +321,16 @@ const handleRightRemove = () => {}
                 ></el-input>
                 <div class="actions">
                   <div>
-                    <el-checkbox v-model="fieldItem.isFilter">Filter</el-checkbox>
-                    <el-checkbox v-model="fieldItem.isSort">Sort</el-checkbox>
+                    <el-checkbox
+                      :disabled="fieldItem.fieldType !== 'System'"
+                      v-model="fieldItem.isFilter"
+                      >Filter</el-checkbox
+                    >
+                    <el-checkbox
+                      :disabled="fieldItem.fieldType !== 'System'"
+                      v-model="fieldItem.isSort"
+                      >Sort</el-checkbox
+                    >
                   </div>
                   <span
                     @click="handleDeleteField(fieldItem.field)"
@@ -271,7 +345,7 @@ const handleRightRemove = () => {}
       <div class="report-access-control template-box">
         <div class="header">Report Access Control</div>
         <div class="content-box">
-          <el-radio-group class="radio-group" v-model="reportAccessControlRadio">
+          <el-radio-group class="radio-group" v-model="accessControlType">
             <el-radio class="radio-item" value="All Users">
               <template #default>
                 <div class="radio-content">
@@ -291,7 +365,7 @@ const handleRightRemove = () => {}
                   </div>
                   <div
                     class="extended-filter"
-                    v-if="reportAccessControlRadio === 'Specific Roles'"
+                    v-show="accessControlType === 'Specific Roles'"
                     ref="detailRef"
                   >
                     <div class="dividing-line"></div>
@@ -300,14 +374,20 @@ const handleRightRemove = () => {}
                         <span style="color: var(--color-danger)">*</span>
                         <span>Party ID</span>
                       </div>
-                      <partyIDSelect></partyIDSelect>
+                      <partyIDSelect
+                        @change-data="changePartyId"
+                        :data="specificRoles.partyId"
+                      ></partyIDSelect>
                     </div>
                     <div class="filter-item">
                       <div class="label">
                         <span style="color: var(--color-danger)">*</span>
                         <span>Group Name</span>
                       </div>
-                      <GroupNameSelect></GroupNameSelect>
+                      <GroupNameSelect
+                        @change-data="changeGroupName"
+                        :data="specificRoles.groupName"
+                      ></GroupNameSelect>
                     </div>
                   </div>
                 </div>

+ 1 - 3
src/views/TemplateManagement/src/components/CreateReportTemplate/src/components/AdjustmentField.vue

@@ -319,6 +319,7 @@ const handleApply = () => {
   //   })
   console.log('selectColumns.value', selectColumns.value)
   emits('apply', selectColumns.value)
+  dialogVisible.value = false
 }
 
 const clearData = () => {
@@ -464,9 +465,6 @@ defineExpose({
         @click="dialogVisible = false"
         >Cancel</el-button
       >
-      <el-button type="default" style="height: 40px; padding: 8px 20px" @click="handleReset"
-        >Reset to default</el-button
-      >
       <el-button
         class="el-button--dark"
         style="height: 40px; padding: 8px 40px"

+ 54 - 87
src/views/TemplateManagement/src/components/CreateReportTemplate/src/components/GroupNameSelect.vue

@@ -1,98 +1,59 @@
 <script setup lang="ts">
+import { cloneDeep } from 'lodash'
+
+const props = defineProps({
+  data: {
+    type: Array as () => string[],
+    default: () => []
+  }
+})
+const selectData = ref<string[]>([])
+watch(
+  () => props.data,
+  () => {
+    selectData.value = cloneDeep(props.data) || []
+  },
+  {
+    deep: true,
+    immediate: true
+  }
+)
+const emit = defineEmits(['changeData'])
+const changeData = (val: string[]) => {
+  // 同步选中状态
+  emit('changeData', val)
+}
+
 interface ListItem {
-  value: string
+  id: string
   label: string
   checked: boolean
 }
-
-const list = ref<ListItem[]>([])
 const options = ref<ListItem[]>([])
-const selectData = ref<string[]>([])
 const loading = ref(false)
 
-const states = [
-  'GRNAME000010',
-  'GRNAME000012',
-  'GRNAME000013',
-  'GRNAME000014',
-  'GRNAME000014',
-  'GRNAME000015',
-  'GRNAME000016',
-  'GRNAME000017',
-  'GRNAME000018',
-  'GRNAME000019'
-]
-
 onMounted(() => {
-  list.value = states.map((item) => ({
-    value: `value:${item}LBR700011,DKCN000013,DKCN000011,DKCN000010,DKCN000010,DKCN000010,DKCN000010,DKCN000010,DKCN000010,LBR700011,DKCN000013,DKCN000011,DKCN000010,DKCN000010,DKCN000010,DKCN000010,DKCN000010,DKCN000010`,
-    label: `label:${item}`,
-    checked: false
-  }))
-  options.value = [...list.value]
+  options.value = []
 })
 
 // 搜索方法
 const remoteMethod = (query: string) => {
-  // if (query) {
   loading.value = true
   $api
     .getSpecificRolesGroupName({ term: query })
     .then((res: any) => {
       if (res.code == 200) {
         options.value = res.data.map((item: any) => ({
-          value: item.id,
+          id: item.id,
           label: item.label,
           code: item.code,
           checked: false
         }))
       }
-      // list.value = res.data.map((item: string) => ({
-      //   value: item,
-      //   label: item,
-      //   checked: false
-      // }))
     })
     .finally(() => {
       loading.value = false
     })
-  // setTimeout(() => {
-
-  //   options.value = list.value.filter((item) => {
-  //     return item.label.toLowerCase().includes(query.toLowerCase())
-  //   })
-  //   syncCheckedState()
-  // }, 200)
-  // } else {
-  //   options.value = [...list.value]
-  //   syncCheckedState()
-  // }
-}
-
-const syncCheckedState = () => {
-  options.value.forEach((item) => {
-    item.checked = selectData.value.includes(item.value)
-  })
-}
-
-watch(
-  () => selectData.value,
-  () => {
-    syncCheckedState()
-  },
-  { immediate: true, deep: true }
-)
-
-const handleCheckboxChange = (item: ListItem) => {
-  // 先翻转状态
-  item.checked = !item.checked
-
-  const index = selectData.value.indexOf(item.value)
-  if (item.checked && index === -1) {
-    selectData.value.push(item.value)
-  } else if (!item.checked && index > -1) {
-    selectData.value.splice(index, 1)
-  }
 }
 
 const testRef = ref(null)
@@ -106,30 +67,30 @@ onMounted(() => {
     v-model="selectData"
     multiple
     filterable
-    remote
     reserve-keyword
     placeholder="Select Group Name (Multi-select allowed)"
-    :remote-method="remoteMethod"
     :loading="loading"
     style="width: 100%"
     ref="testRef"
     popper-class="group-name-select-popper"
+    :filter-method="remoteMethod"
+    @change="changeData"
   >
-    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
-      <div class="select-option">
-        <el-checkbox
-          :model-value="item.checked"
-          @change="handleCheckboxChange(item)"
-          @click.stop
-          @mousedown.prevent
-          style="height: 22px"
-        >
-          {{ item.label }}
-        </el-checkbox>
-        <span :style="{ width: testRef ? testRef?.$el?.offsetWidth - 70 + 'px' : 'auto' }">{{
-          item.value
-        }}</span>
-      </div>
+    <el-option
+      v-for="item in options"
+      :key="item.id + item.label"
+      :label="item.label"
+      :value="item.label"
+    >
+      <!-- 只用于显示,不控制逻辑 -->
+      <el-checkbox :model-value="selectData.includes(item.label)" style="flex: 1">
+        <div class="select-option">
+          <span>{{ item.label }}</span>
+          <span class="value" :style="{ width: testRef?.$el?.offsetWidth - 70 + 'px' }">
+            {{ item.id }}
+          </span>
+        </div>
+      </el-checkbox>
     </el-option>
   </el-select>
 </template>
@@ -141,18 +102,21 @@ onMounted(() => {
   flex-direction: column;
   align-items: flex-start;
   max-width: 100%;
+  gap: 3px;
+  padding-top: 3px;
   :deep(.el-checkbox__label) {
     font-weight: 700;
   }
-  & > span {
-    margin-left: 24px;
+  & > .value {
     // width: 100%;
     white-space: wrap;
     font-size: 12px;
     line-height: 16px;
-    color: var(--color-neutral-2);
   }
 }
+.value {
+  color: var(--color-neutral-2);
+}
 
 :deep(.el-checkbox__inner) {
   height: 16px;
@@ -173,5 +137,8 @@ onMounted(() => {
     height: auto;
     padding: 8px;
   }
+  .el-checkbox__input {
+    align-self: flex-start;
+  }
 }
 </style>

+ 51 - 63
src/views/TemplateManagement/src/components/CreateReportTemplate/src/components/PartyIDSelect.vue

@@ -1,103 +1,86 @@
 <script setup lang="ts">
+import { cloneDeep } from 'lodash'
+
+const props = defineProps({
+  data: {
+    type: Array as () => string[],
+    default: () => []
+  }
+})
+
+const selectData = ref<string[]>([])
+watch(
+  () => props.data,
+  (newValue) => {
+    console.log('Props data changed:', newValue)
+    selectData.value = cloneDeep(newValue) || []
+  },
+  {
+    deep: true,
+    immediate: true
+  }
+)
+const emit = defineEmits(['changeData'])
+const changeData = (val: string[]) => {
+  console.log('Selected Party IDs:', val)
+  // 同步选中状态
+  emit('changeData', val)
+}
+
 interface ListItem {
   label: string
   id: string
-  checked: boolean
 }
 
-const list = ref<ListItem[]>([])
 const options = ref<ListItem[]>([])
-const selectData = ref<string[]>([])
 const loading = ref(false)
 
-const states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas']
-
-onMounted(() => {
-  options.value = []
-})
-
 // 搜索方法
 const remoteMethod = (query: string) => {
-  // if (query) {
   loading.value = true
   $api
     .getSpecificRolesPartyID({ term: query })
     .then((res: any) => {
       if (res.code === 200) {
-        options.value = res.data?.map((item: any) => ({
+        options.value = (res.data || []).map((item: any) => ({
           id: item.id,
-          label: item.label,
-          checked: false
+          label: item.label
         }))
       }
     })
     .finally(() => {
       loading.value = false
     })
-  // syncCheckedState()
-  // setTimeout(() => {
-  //   loading.value = false
-  //   options.value = list.value.filter((item) => {
-  //     return item.label.toLowerCase().includes(query.toLowerCase())
-  //   })
-  // }, 200)
-  // } else {
-  //   options.value = [...list.value]
-  //   syncCheckedState()
-  // }
 }
 
-const syncCheckedState = () => {
-  options.value.forEach((item) => {
-    item.checked = selectData.value.includes(item.value)
-  })
-}
-
-watch(
-  () => selectData.value,
-  () => {
-    syncCheckedState()
-  },
-  { immediate: true, deep: true }
-)
-
-const handleCheckboxChange = (item: ListItem) => {
-  // // 先翻转状态
-  // item.checked = !item.checked
-  // const index = selectData.value.indexOf(item.id)
-  // if (item.checked && index === -1) {
-  //   selectData.value.push(item.id)
-  // } else if (!item.checked && index > -1) {
-  //   selectData.value.splice(index, 1)
-  // }
-}
+// 首次聚焦或输入时加载(可选:如果希望空搜也加载)
+// 但通常 remote 场景是“输入才搜”,所以这里只在 filter 时调用
 </script>
 
 <template>
   <el-select
-    v-model="selectData"
+    :model-value="selectData"
     multiple
     filterable
-    remote
     reserve-keyword
     placeholder="Select Party IDs (Multi-select allowed)"
-    :remote-method="remoteMethod"
     :loading="loading"
     style="width: 100%"
     popper-class="part-id-select-popper"
+    :filter-method="remoteMethod"
+    @change="changeData"
   >
-    <el-option v-for="item in options" :key="item.id" :label="item.id" :value="item.id">
+    <el-option
+      v-for="item in options"
+      :key="item.id + item.label"
+      :label="item.label"
+      :value="item.label"
+    >
       <div class="select-option">
-        <el-checkbox
-          :model-value="item.checked"
-          @change="handleCheckboxChange(item)"
-          @click.stop
-          @mousedown.prevent
-          style="width: 220px"
-        >
-          {{ item.label }}
+        <el-checkbox :model-value="selectData.includes(item.label)" style="flex: 1">
+          <span style="flex: 1; display: inline-block; width: 320px">{{ item.label }}</span>
+          <span style="width: 200px">{{ item.id }}</span>
         </el-checkbox>
-        <span>{{ item.id }}</span>
       </div>
     </el-option>
   </el-select>
@@ -126,11 +109,16 @@ const handleCheckboxChange = (item: ListItem) => {
     top: 0;
   }
 }
+:deep(.el-checkbox__label) {
+  flex: 1;
+  display: flex;
+}
 </style>
 
 <style lang="scss">
 .part-id-select-popper {
-  width: 480px !important;
-  min-width: unset !important;
+  // width: 100% !important;
+  // width: auto;
+  // min-width: unset !important;
 }
 </style>

+ 38 - 3
src/views/TemplateManagement/src/components/TableView/src/TableView.vue

@@ -40,7 +40,7 @@ const tableColumns = [
   {
     title: 'Creation Date',
     type: 'normal',
-    field: 'creation_time',
+    field: 'created_time',
     formatter: 'dateTime',
     sortable: true
   }
@@ -89,12 +89,26 @@ const handleColumns = (columns: any) => {
 // 获取表格列
 const getTableColumns = async () => {
   tableData.value.columns = [
-    { title: 'Action', width: 116, fixed: 'left', slots: { default: 'action' } },
+    { title: 'Action', width: 120, fixed: 'left', slots: { default: 'action' } },
     ...handleColumns(tableColumns)
   ]
   // tableRef.value && autoWidth(tableData.value, tableRef.value)
 }
 
+const handleClick = (row: any, isActive: boolean) => {
+  $api
+    .changeReportTemplateIsActive({
+      serial_no: row.serial_no,
+      is_active: isActive
+    })
+    .then((res: any) => {
+      if (res.code === 200) {
+        row.is_active = isActive ? 't' : 'f'
+        // getTableData(true)
+      }
+    })
+}
+
 const pageInfo = ref({ pageNo: 1, pageSize: 20, total: 0 })
 // 获得表格数据后赋值
 const assignTableData = (data: any) => {
@@ -231,6 +245,20 @@ const tableData = ref<VxeGridProps<any>>({
   }
 })
 
+const handleEdit = (serial_no: string) => {
+  router.push({
+    name: 'Create Report Template',
+    query: { serial_no }
+  })
+}
+
+const handleCopy = (serial_no: string) => {
+  router.push({
+    name: 'Create Report Template',
+    query: { serial_no, isCopy: 't' }
+  })
+}
+
 // 实现行点击样式
 useRowClickStyle(tableRef)
 
@@ -261,6 +289,7 @@ defineExpose({
       <template #action="{ row }">
         <el-button
           class="el-button--blue"
+          @click="handleEdit(row.serial_no)"
           style="height: 24px; padding: 8px 4px; padding-left: 5px; font-size: 12px"
         >
           <span
@@ -279,6 +308,8 @@ defineExpose({
         </el-button>
         <el-button
           class="el-button--blue"
+          v-if="row.is_active === 't'"
+          @click="handleClick(row, false)"
           style="height: 24px; padding: 8px 4px; padding-left: 5px; font-size: 12px"
         >
           <span
@@ -288,6 +319,8 @@ defineExpose({
         </el-button>
         <el-button
           class="el-button--blue"
+          v-if="row.is_active === 'f'"
+          @click="handleClick(row, true)"
           style="height: 24px; padding: 8px 4px; padding-left: 5px; font-size: 12px"
         >
           <span
@@ -298,7 +331,9 @@ defineExpose({
       </template>
       <!-- Status字段的插槽 -->
       <template #status="{ row, column }">
-        <VTag :type="row[column.field]">{{ row[column.field] }}</VTag>
+        <VTag :type="row[column.field] === 't' ? 'Active' : 'Inactive'">{{
+          row[column.field] === 't' ? 'Active' : 'Inactive'
+        }}</VTag>
       </template>
       <!-- 空数据时的插槽 -->
       <template #empty v-if="!tableLoadingTableData && tableData.data.length === 0">