Explorar o código

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

Jack Zhou hai 1 mes
pai
achega
c3a7c55978

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

@@ -7,7 +7,7 @@ const baseUrl = `${base}/main_new_version.php`
  * 获取report template management表格列数据
  * 获取report template management表格列数据
  */
  */
 export const getReportTemplateManagementTable = (params: any, config: any) => {
 export const getReportTemplateManagementTable = (params: any, config: any) => {
-  return HttpAxios.get(
+  return HttpAxios.post(
     `${baseUrl}`,
     `${baseUrl}`,
     {
     {
       action: 'report_config',
       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 列表数据
  * 获取Report Fields Configuration 列表数据
  */
  */
@@ -64,4 +79,35 @@ export const getSpecificRolesGroupName = (params: any, config: any) => {
     },
     },
     config
     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'
     | 'Pending Approval'
     | 'Approved'
     | 'Approved'
     | 'Rejected'
     | 'Rejected'
+    | 'Active'
+    | 'Inactive'
   large?: boolean
   large?: boolean
 }
 }
 
 
@@ -28,7 +30,9 @@ const mappingTable = new Map([
   ['Arrived', 'arrived'],
   ['Arrived', 'arrived'],
   ['Completed', 'completed'],
   ['Completed', 'completed'],
   ['Departed', 'Departed'],
   ['Departed', 'Departed'],
-  ['Pending Approval', 'pending-approval']
+  ['Pending Approval', 'pending-approval'],
+  ['Active', 'active'],
+  ['Inactive', 'inactive']
 ])
 ])
 defineProps<internalProps>()
 defineProps<internalProps>()
 </script>
 </script>
@@ -135,6 +139,20 @@ defineProps<internalProps>()
       background-color: var(--color-tag-unfinished-approval);
       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 {
   &.v-tag__approved {
     background-color: var(--color-tag-approved-bg);
     background-color: var(--color-tag-approved-bg);
     color: var(--color-tag-approved);
     color: var(--color-tag-approved);

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

@@ -21,7 +21,6 @@ const whiteList = [
   'Create New Booking',
   'Create New Booking',
   'Destination Create New Rule',
   'Destination Create New Rule',
   "Create Report Template",
   "Create Report Template",
-  'Report Management'
 ]
 ]
 
 
 export const useBreadCrumb = defineStore('breadCrumb', {
 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
   rollingStartDate.value = data.rollingStartDate
   rollingEndDate.value = data.rollingEndDate
   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>
 </script>
 <template>
 <template>
   <div class="Title">
   <div class="Title">

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

@@ -26,12 +26,12 @@ const aiModelList = [
 
 
 const activeOptions = [
 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 tableRef = ref()
 
 
 const Search = () => {
 const Search = () => {
-  tableRef.value.SearchOperationLog(queryData.value)
+  tableRef.value.searchTableData(queryData.value)
 }
 }
 
 
 const handleCreate = () => {
 const handleCreate = () => {

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

@@ -1,42 +1,63 @@
 <script lang="ts" setup>
 <script lang="ts" setup>
-import { useRouter } from 'vue-router'
+import { useRouter, useRoute } from 'vue-router'
 import partyIDSelect from './components/partyIDSelect.vue'
 import partyIDSelect from './components/partyIDSelect.vue'
 import GroupNameSelect from './components/GroupNameSelect.vue'
 import GroupNameSelect from './components/GroupNameSelect.vue'
 import { VueDraggable } from 'vue-draggable-plus'
 import { VueDraggable } from 'vue-draggable-plus'
 import AdjustmentField from './components/AdjustmentField.vue'
 import AdjustmentField from './components/AdjustmentField.vue'
 
 
 const router = useRouter()
 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({
 const infoData = ref({
   reportName: '',
   reportName: '',
   reportLevel: '',
   reportLevel: '',
   reportDescription: ''
   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 {
 interface Field {
   field: string
   field: string
   title: string
   title: string
   displayName: string
   displayName: string
+  fieldType: string
   value?: string
   value?: string
   isFilter: boolean
   isFilter: boolean
   isSort: boolean
   isSort: boolean
@@ -64,6 +85,10 @@ const handleDeleteField = (field: string) => {
 const AdjustmentFieldRef = ref()
 const AdjustmentFieldRef = ref()
 // 打开定制表格弹窗
 // 打开定制表格弹窗
 const handleCustomizeColumns = () => {
 const handleCustomizeColumns = () => {
+  if (!infoData.value.reportLevel) {
+    ElMessage.warning('Please select the report level.')
+    return
+  }
   const params = {
   const params = {
     serial_no: '',
     serial_no: '',
     level: infoData.value.reportLevel
     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'
     'Drag item over to this selection or click "add" icon to show the field on report template list'
   )
   )
 }
 }
-// 定制表格
-const customizeColumns = async () => {}
 
 
 const newFieldInfo = ref<{
 const newFieldInfo = ref<{
   name: string
   name: string
@@ -95,60 +118,105 @@ const handleFieldTypeChange = () => {
   newFieldInfo.value.value = ''
   newFieldInfo.value.value = ''
 }
 }
 const addNewField = () => {
 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.')
     ElMessage.warning('Please enter the new field name.')
     return
     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) => {
 const handleApplay = (data: any) => {
   console.log('data', data)
   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)
 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 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>
 </script>
 <template>
 <template>
-  <div class="dashboard">
+  <div class="dashboard" v-vloading="pageLoading">
     <div class="Title">
     <div class="Title">
       <span>Create New Report Template</span>
       <span>Create New Report Template</span>
       <div class="button-group">
       <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
           <span class="font_family icon-icon_return_b" style="margin-right: 3px"></span
           >Cancel</el-button
           >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
           <span class="font_family icon-icon_save_b" style="margin-right: 3px"></span
           >Save</el-button
           >Save</el-button
         >
         >
@@ -227,7 +295,7 @@ const handleRightRemove = () => {}
           </div>
           </div>
           <div class="fields-list" v-else>
           <div class="fields-list" v-else>
             <VueDraggable
             <VueDraggable
-              v-vloading="loading"
+              v-vloading="fieldLoading"
               v-model="fieldsList"
               v-model="fieldsList"
               class="column-list"
               class="column-list"
               ghost-class="ghost-column"
               ghost-class="ghost-column"
@@ -243,10 +311,8 @@ const handleRightRemove = () => {}
                   style="margin-right: 12px; font-size: 16px"
                   style="margin-right: 12px; font-size: 16px"
                 ></span>
                 ></span>
                 <div class="label">
                 <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>
                 </div>
                 <el-input
                 <el-input
                   class="display-name"
                   class="display-name"
@@ -255,8 +321,16 @@ const handleRightRemove = () => {}
                 ></el-input>
                 ></el-input>
                 <div class="actions">
                 <div class="actions">
                   <div>
                   <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>
                   </div>
                   <span
                   <span
                     @click="handleDeleteField(fieldItem.field)"
                     @click="handleDeleteField(fieldItem.field)"
@@ -271,7 +345,7 @@ const handleRightRemove = () => {}
       <div class="report-access-control template-box">
       <div class="report-access-control template-box">
         <div class="header">Report Access Control</div>
         <div class="header">Report Access Control</div>
         <div class="content-box">
         <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">
             <el-radio class="radio-item" value="All Users">
               <template #default>
               <template #default>
                 <div class="radio-content">
                 <div class="radio-content">
@@ -291,7 +365,7 @@ const handleRightRemove = () => {}
                   </div>
                   </div>
                   <div
                   <div
                     class="extended-filter"
                     class="extended-filter"
-                    v-if="reportAccessControlRadio === 'Specific Roles'"
+                    v-show="accessControlType === 'Specific Roles'"
                     ref="detailRef"
                     ref="detailRef"
                   >
                   >
                     <div class="dividing-line"></div>
                     <div class="dividing-line"></div>
@@ -300,14 +374,20 @@ const handleRightRemove = () => {}
                         <span style="color: var(--color-danger)">*</span>
                         <span style="color: var(--color-danger)">*</span>
                         <span>Party ID</span>
                         <span>Party ID</span>
                       </div>
                       </div>
-                      <partyIDSelect></partyIDSelect>
+                      <partyIDSelect
+                        @change-data="changePartyId"
+                        :data="specificRoles.partyId"
+                      ></partyIDSelect>
                     </div>
                     </div>
                     <div class="filter-item">
                     <div class="filter-item">
                       <div class="label">
                       <div class="label">
                         <span style="color: var(--color-danger)">*</span>
                         <span style="color: var(--color-danger)">*</span>
                         <span>Group Name</span>
                         <span>Group Name</span>
                       </div>
                       </div>
-                      <GroupNameSelect></GroupNameSelect>
+                      <GroupNameSelect
+                        @change-data="changeGroupName"
+                        :data="specificRoles.groupName"
+                      ></GroupNameSelect>
                     </div>
                     </div>
                   </div>
                   </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)
   console.log('selectColumns.value', selectColumns.value)
   emits('apply', selectColumns.value)
   emits('apply', selectColumns.value)
+  dialogVisible.value = false
 }
 }
 
 
 const clearData = () => {
 const clearData = () => {
@@ -464,9 +465,6 @@ defineExpose({
         @click="dialogVisible = false"
         @click="dialogVisible = false"
         >Cancel</el-button
         >Cancel</el-button
       >
       >
-      <el-button type="default" style="height: 40px; padding: 8px 20px" @click="handleReset"
-        >Reset to default</el-button
-      >
       <el-button
       <el-button
         class="el-button--dark"
         class="el-button--dark"
         style="height: 40px; padding: 8px 40px"
         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">
 <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 {
 interface ListItem {
-  value: string
+  id: string
   label: string
   label: string
   checked: boolean
   checked: boolean
 }
 }
-
-const list = ref<ListItem[]>([])
 const options = ref<ListItem[]>([])
 const options = ref<ListItem[]>([])
-const selectData = ref<string[]>([])
 const loading = ref(false)
 const loading = ref(false)
 
 
-const states = [
-  'GRNAME000010',
-  'GRNAME000012',
-  'GRNAME000013',
-  'GRNAME000014',
-  'GRNAME000014',
-  'GRNAME000015',
-  'GRNAME000016',
-  'GRNAME000017',
-  'GRNAME000018',
-  'GRNAME000019'
-]
-
 onMounted(() => {
 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) => {
 const remoteMethod = (query: string) => {
-  // if (query) {
   loading.value = true
   loading.value = true
   $api
   $api
     .getSpecificRolesGroupName({ term: query })
     .getSpecificRolesGroupName({ term: query })
     .then((res: any) => {
     .then((res: any) => {
       if (res.code == 200) {
       if (res.code == 200) {
         options.value = res.data.map((item: any) => ({
         options.value = res.data.map((item: any) => ({
-          value: item.id,
+          id: item.id,
           label: item.label,
           label: item.label,
           code: item.code,
           code: item.code,
           checked: false
           checked: false
         }))
         }))
       }
       }
-      // list.value = res.data.map((item: string) => ({
-      //   value: item,
-      //   label: item,
-      //   checked: false
-      // }))
     })
     })
     .finally(() => {
     .finally(() => {
       loading.value = false
       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)
 const testRef = ref(null)
@@ -106,30 +67,30 @@ onMounted(() => {
     v-model="selectData"
     v-model="selectData"
     multiple
     multiple
     filterable
     filterable
-    remote
     reserve-keyword
     reserve-keyword
     placeholder="Select Group Name (Multi-select allowed)"
     placeholder="Select Group Name (Multi-select allowed)"
-    :remote-method="remoteMethod"
     :loading="loading"
     :loading="loading"
     style="width: 100%"
     style="width: 100%"
     ref="testRef"
     ref="testRef"
     popper-class="group-name-select-popper"
     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-option>
   </el-select>
   </el-select>
 </template>
 </template>
@@ -141,18 +102,21 @@ onMounted(() => {
   flex-direction: column;
   flex-direction: column;
   align-items: flex-start;
   align-items: flex-start;
   max-width: 100%;
   max-width: 100%;
+  gap: 3px;
+  padding-top: 3px;
   :deep(.el-checkbox__label) {
   :deep(.el-checkbox__label) {
     font-weight: 700;
     font-weight: 700;
   }
   }
-  & > span {
-    margin-left: 24px;
+  & > .value {
     // width: 100%;
     // width: 100%;
     white-space: wrap;
     white-space: wrap;
     font-size: 12px;
     font-size: 12px;
     line-height: 16px;
     line-height: 16px;
-    color: var(--color-neutral-2);
   }
   }
 }
 }
+.value {
+  color: var(--color-neutral-2);
+}
 
 
 :deep(.el-checkbox__inner) {
 :deep(.el-checkbox__inner) {
   height: 16px;
   height: 16px;
@@ -173,5 +137,8 @@ onMounted(() => {
     height: auto;
     height: auto;
     padding: 8px;
     padding: 8px;
   }
   }
+  .el-checkbox__input {
+    align-self: flex-start;
+  }
 }
 }
 </style>
 </style>

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

@@ -1,103 +1,86 @@
 <script setup lang="ts">
 <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 {
 interface ListItem {
   label: string
   label: string
   id: string
   id: string
-  checked: boolean
 }
 }
 
 
-const list = ref<ListItem[]>([])
 const options = ref<ListItem[]>([])
 const options = ref<ListItem[]>([])
-const selectData = ref<string[]>([])
 const loading = ref(false)
 const loading = ref(false)
 
 
-const states = ['Alabama', 'Alaska', 'Arizona', 'Arkansas']
-
-onMounted(() => {
-  options.value = []
-})
-
 // 搜索方法
 // 搜索方法
 const remoteMethod = (query: string) => {
 const remoteMethod = (query: string) => {
-  // if (query) {
   loading.value = true
   loading.value = true
   $api
   $api
     .getSpecificRolesPartyID({ term: query })
     .getSpecificRolesPartyID({ term: query })
     .then((res: any) => {
     .then((res: any) => {
       if (res.code === 200) {
       if (res.code === 200) {
-        options.value = res.data?.map((item: any) => ({
+        options.value = (res.data || []).map((item: any) => ({
           id: item.id,
           id: item.id,
-          label: item.label,
-          checked: false
+          label: item.label
         }))
         }))
       }
       }
     })
     })
     .finally(() => {
     .finally(() => {
       loading.value = false
       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>
 </script>
 
 
 <template>
 <template>
   <el-select
   <el-select
-    v-model="selectData"
+    :model-value="selectData"
     multiple
     multiple
     filterable
     filterable
-    remote
     reserve-keyword
     reserve-keyword
     placeholder="Select Party IDs (Multi-select allowed)"
     placeholder="Select Party IDs (Multi-select allowed)"
-    :remote-method="remoteMethod"
     :loading="loading"
     :loading="loading"
     style="width: 100%"
     style="width: 100%"
     popper-class="part-id-select-popper"
     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">
       <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>
         </el-checkbox>
-        <span>{{ item.id }}</span>
       </div>
       </div>
     </el-option>
     </el-option>
   </el-select>
   </el-select>
@@ -126,11 +109,16 @@ const handleCheckboxChange = (item: ListItem) => {
     top: 0;
     top: 0;
   }
   }
 }
 }
+:deep(.el-checkbox__label) {
+  flex: 1;
+  display: flex;
+}
 </style>
 </style>
 
 
 <style lang="scss">
 <style lang="scss">
 .part-id-select-popper {
 .part-id-select-popper {
-  width: 480px !important;
-  min-width: unset !important;
+  // width: 100% !important;
+  // width: auto;
+  // min-width: unset !important;
 }
 }
 </style>
 </style>

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

@@ -40,7 +40,7 @@ const tableColumns = [
   {
   {
     title: 'Creation Date',
     title: 'Creation Date',
     type: 'normal',
     type: 'normal',
-    field: 'creation_time',
+    field: 'created_time',
     formatter: 'dateTime',
     formatter: 'dateTime',
     sortable: true
     sortable: true
   }
   }
@@ -89,12 +89,26 @@ const handleColumns = (columns: any) => {
 // 获取表格列
 // 获取表格列
 const getTableColumns = async () => {
 const getTableColumns = async () => {
   tableData.value.columns = [
   tableData.value.columns = [
-    { title: 'Action', width: 116, fixed: 'left', slots: { default: 'action' } },
+    { title: 'Action', width: 120, fixed: 'left', slots: { default: 'action' } },
     ...handleColumns(tableColumns)
     ...handleColumns(tableColumns)
   ]
   ]
   // tableRef.value && autoWidth(tableData.value, tableRef.value)
   // 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 pageInfo = ref({ pageNo: 1, pageSize: 20, total: 0 })
 // 获得表格数据后赋值
 // 获得表格数据后赋值
 const assignTableData = (data: any) => {
 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)
 useRowClickStyle(tableRef)
 
 
@@ -261,6 +289,7 @@ defineExpose({
       <template #action="{ row }">
       <template #action="{ row }">
         <el-button
         <el-button
           class="el-button--blue"
           class="el-button--blue"
+          @click="handleEdit(row.serial_no)"
           style="height: 24px; padding: 8px 4px; padding-left: 5px; font-size: 12px"
           style="height: 24px; padding: 8px 4px; padding-left: 5px; font-size: 12px"
         >
         >
           <span
           <span
@@ -279,6 +308,8 @@ defineExpose({
         </el-button>
         </el-button>
         <el-button
         <el-button
           class="el-button--blue"
           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"
           style="height: 24px; padding: 8px 4px; padding-left: 5px; font-size: 12px"
         >
         >
           <span
           <span
@@ -288,6 +319,8 @@ defineExpose({
         </el-button>
         </el-button>
         <el-button
         <el-button
           class="el-button--blue"
           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"
           style="height: 24px; padding: 8px 4px; padding-left: 5px; font-size: 12px"
         >
         >
           <span
           <span
@@ -298,7 +331,9 @@ defineExpose({
       </template>
       </template>
       <!-- Status字段的插槽 -->
       <!-- Status字段的插槽 -->
       <template #status="{ row, column }">
       <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>
       <!-- 空数据时的插槽 -->
       <!-- 空数据时的插槽 -->
       <template #empty v-if="!tableLoadingTableData && tableData.data.length === 0">
       <template #empty v-if="!tableLoadingTableData && tableData.data.length === 0">