Răsfoiți Sursa

协议组件

@dongkboy 1 an în urmă
părinte
comite
1d7697359e

+ 72 - 0
src/components/SearchForm/index.vue

@@ -0,0 +1,72 @@
+<template>
+  <ElForm :inline="false" :model="formInline" class="demo-form-inline" label-width="100px">
+    <ElRow :gutter="20">
+      <ElCol v-for="(field, index) in fields" :key="index" :md="8">
+        <ElFormItem :label="field.label">
+          <component v-if="field.type === 'input'" is="el-input" v-model="formInline[field.model]"
+            :placeholder="field.placeholder" clearable class="el-inputs" />
+          <component v-else-if="field.type === 'select'" is="el-select" v-model="formInline[field.model]"
+            :placeholder="field.placeholder" clearable class="el-inputs">
+            <el-option v-for="(item, index) in field.options" :key="index" :label="item.label" :value="item.value" />
+          </component>
+          <component v-else-if="field.type === 'cascader'" is="el-cascader" v-model="formInline[field.model]"
+            :options="field.options" :props="field.props" filterable clearable @change="field.onChange"
+            class="el-inputs" />
+          <component v-else-if="field.type === 'date'" is="el-date-picker" v-model="formInline[field.model]"
+            :type="field.dateType" range-separator="至" :start-placeholder="field.startplaceholder"
+            format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss"
+            :end-placeholder="field.endplaceholder" clearable @change="field.onChange" />
+        </ElFormItem>
+      </ElCol>
+      <ElCol :md="4" >
+        <ElFormItem>
+          <div class="flex j-end" style="width: 100%;">
+            <el-button type="primary" @click="handleSearch">
+              <template #icon>
+                <SvgIcon name="i-ep:search" />
+              </template>
+              查询
+            </el-button>
+            <el-button type="default" @click="handleReset">重置</el-button>
+          </div>
+        </ElFormItem>
+      </ElCol>
+    </ElRow>
+  </ElForm>
+</template>
+
+<script lang="ts" setup>
+import { defineProps } from "vue";
+
+const props = defineProps<{
+  fields: Array<{
+    label: string; // 字段标签
+    model: string; // v-model 绑定的字段名
+    type: string; // 字段类型 ('input', 'select', 'cascader', 'date')
+    placeholder?: string; // 占位符
+    options?: Array<{ [key: string]: any }>; // 选项列表
+    props?: any; // Cascader 组件的其他 props
+    onChange?: (value: any) => void; // 变化事件
+    dateType?: string; // 日期选择器类型
+    [key: string]: any,
+  }>; // 字段信息数组
+  formInline: any; // 表单数据
+  onSearch: () => void; // 查询事件
+  onReset: () => void; // 重置事件
+}>();
+onBeforeMount(() => {
+  console.log(props)
+})
+const handleSearch = () => {
+  props.onSearch(); // 调用父组件的查询事件
+};
+
+const handleReset = () => {
+  props.onReset(); // 调用父组件的重置事件
+};
+</script>
+<style lang="scss">
+.el-inputs {
+  width: 100% !important;
+}
+</style>

+ 209 - 0
src/components/TableTree/index.vue

@@ -0,0 +1,209 @@
+<template>
+  <div class="containerTable">
+    <div class="table_box">
+      <div class="table-title-btn">
+        <slot name="table-title-btn"></slot>
+      </div>
+      <el-table ref="TableTreeRef" class="custom-table" v-loading="props.loading"
+        :header-cell-style="{ 'background-color': '#EEF1F6', 'border-bottom': '1px solid #EEF1F6', 'font-size': '15px', 'color': '#333', 'padding': '10px 0' }"
+        :data="props.tableData" :height="tableHeight" row-key="id"
+         style="width: 100%;">
+        <!-- 空内容自定义 -->
+        <template #empty>
+          <div class="flex f-c a-c ">
+            <img src="../../assets/images/empty.png" alt="">
+            <span style="font-size: 14px;color: #909399;">暂无数据</span>
+          </div>
+        </template>
+        <el-table-column type="selection" v-if="showSelect" :selectable="selectable" width="55" />
+        <el-table-column v-if="showIndex" type="index" label="序号" width="55" />
+        <el-table-column v-for="column in columns" :key="column.prop" :prop="column.prop" :label="column.label"
+          :sortable="column.sortable ? 'custom' : false" :width="column.width" :align="column.align?column.align:'center'" >
+          <template #default="scope">
+            <RouterLink v-if="column.component === 'RouterLink'" :to="getRouterLinkTo(scope.row, column)" class="custom-link">
+              {{ scope.row[column.prop] }}
+            </RouterLink>
+            <el-tag v-else-if="column.component === 'Tag'" :type="getTagTypeAndText(scope.row, column).type">
+              {{ getTagTypeAndText(scope.row, column).text }}
+            </el-tag>
+            <ImagePreview v-else-if="column.component === 'Image'" :src="getImgTo(scope.row, column)" width="50px" height="50px"></ImagePreview>
+            <span v-else>
+              {{ getDisplayText(scope.row, column) }}
+            </span>
+          </template>
+          <template #header>
+            <slot name="search" :slotData="column"></slot>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" fixed="right" :width="props.columnwidth" align="center">
+          <template #default="scope">
+            <div class="flex j-c a-c">
+              <slot name="operation" class="operationClass" :operationData="scope.row"></slot>
+            </div>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { defineProps, ref, onMounted, defineEmits } from "vue";
+import type { TableInstance } from "element-plus";
+
+interface TableRow {
+  [key: string]: any;
+}
+interface Row {
+  [key: string]: any; // 假设Row是一个具有任意属性的对象
+}
+interface RouterLink {
+  name: string;
+}
+const emit = defineEmits([]);
+const props = defineProps<{
+  tableData: Array<TableRow>;
+  columnwidth: number,
+  loading?:boolean,
+  columns: {
+    prop: string;
+    label: string;
+    sortable?: boolean;
+    width?: string;
+    style?: string;
+    align?:string,
+    component?:string,
+    formatter?: (row: any, column: any, cellValue: any, index: number) => any;
+
+  }[];
+  showSelect: boolean;
+  showIndex: boolean;
+  tableheight?: (number | string),
+}>();
+const tableHeight = ref(props.tableheight); // 初始化表格高度
+
+const TableTreeRef = ref<TableInstance>();
+const TableData = ref<TableRow[]>();
+onMounted(() => {
+  let counter = 1;
+  TableData.value = props.tableData.map((row) => ({
+    ...row,
+    _edit: false, // 设置默认非编辑状态
+    counter: counter++
+
+  }));
+  setTimeout(() => {
+    const tableElement = TableTreeRef.value?.$el as HTMLElement;
+    if (tableElement) {
+      const offsetTop = tableElement.offsetTop; // 获取 offsetTop
+      let height = window.innerHeight;
+      console.log(height)
+      tableHeight.value = height - offsetTop - 300 + "px";
+    }
+  }, 10);
+
+
+});
+//空值处理
+const displayValue = (value: any) => {
+  return value === null || value === undefined || value === '' ? '-' : value;
+}
+const selectable = () => true;
+// 格式化内容配置
+function getRouterLinkTo(row: Row, column: any): RouterLink {
+  return column.formatter ? column.formatter(row, column, row[column.prop]) : { name: 'OrganizationAdd' };
+}
+function getImgTo(row: Row, column: any) {
+  return row[column.prop];
+}
+function getTagTypeAndText(row: Row, column: any) {
+  // 使用 formatter 返回一个对象,包含 type 和 text
+  return column.formatter ? column.formatter(row, column, row[column.prop]) : { type: 'primary', text: row[column.prop] };
+}
+function getDisplayText(row: Row, column: any): string {
+  return column.formatter ? column.formatter(row, column, row[column.prop]) :displayValue(row[column.prop]);
+}
+</script>
+<style lang="scss" scoped>
+.el-table .el-table__cell .routerlick > a {
+  color: red;
+}
+
+.containerTable {
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  height: auto;
+}
+
+.table_box {
+  flex: 1;
+  margin-bottom: 10px;
+  overflow-y: auto;
+
+  .table_item_container {
+    padding: 0;
+    margin-left: 20px;
+
+    .table_item {
+      margin: 5px 0;
+    }
+  }
+
+  .table-title-btn {
+    margin-bottom: 20px;
+
+    :deep(.el-button) {
+      margin-right: 20px;
+    }
+  }
+}
+
+/* 自定义树状表格图标 */
+
+// /* 有子节点 且未展开 */
+// .custom-table :deep(.el-table__expand-icon) {
+//   display: flex;
+//   align-items: center;
+//   justify-content: center;
+//   width: 18px;
+//   height: 18px;
+//   background: url("../../assets/icons/caretRight.svg") no-repeat;
+//   background-size: auto;
+
+//   svg {
+//     display: none;
+//   }
+// }
+
+// /* 有子节点 且已展开 */
+// .custom-table :deep(.el-table__expand-icon--expanded) {
+//   display: inline-block;
+//   display: flex;
+//   align-items: center;
+//   justify-content: center;
+//   width: 18px;
+//   height: 18px;
+//   content: "";
+//   background: url("../../assets/icons/caretRight.svg") no-repeat;
+//   background-size: auto;
+//   transform: rotate(90deg);
+
+//   svg {
+//     display: none;
+//   }
+// }
+
+:deep(.el-table) {
+  .el-table__row--level-1 {
+    background-color: #eef1f6;
+  }
+}
+
+.operationClass {
+  .el-button {
+    margin: 0 7px;
+  }
+}
+</style>

+ 14 - 0
src/components/empty/index.vue

@@ -0,0 +1,14 @@
+<!-- 模板区域 -->
+<template>
+  <div>
+    <div class="flex f-c a-c " >
+      <img src="../../assets/images/empty.png" alt="">
+      <span style="font-size: 14px;color: #909399;">暂无数据</span>
+    </div>
+  </div>
+</template>
+
+<!-- 行为区域 -->
+<script lang='ts' setup>
+</script>
+<!-- 样式区域 -->

+ 7 - 8
src/components/ruleCondition/index.vue

@@ -75,17 +75,19 @@ const close = () => {
   emits("cancel")
 }
 watch(props, () => {
-  if (props.attrIdList.length) {
+  if (props.attrIdList && props.attrIdList.length) {
     attractivelist.value = props.attrIdList;//获取编辑数据
     const matchedid = matchDataByIds(attractivelist.value);//
-    const matchedinfo=matchDataByInfos(attractivelist.value)
+    const matchedinfo = matchDataByInfos(attractivelist.value)
     Object.keys(checked).forEach(key => { //复选框回显
       checked[key as keyof checkeddata] = matchedid[key] || [];
     });
     Object.keys(checked).forEach(key => {//条件数据回显
       checkeddata[key as keyof checkeddata] = matchedinfo[key] || [];
     });
+
   }
+
 })
 
 const save = () => {
@@ -97,8 +99,6 @@ const save = () => {
     ...checkeddata.InsuranceInformation,
     ...checkeddata.InsuranceCostFactor,
   ]
-  console.log(mergedData)
-  // return;
   emits("save", mergedData)// 返回已选集合
 }
 const attractivelist = ref();
@@ -212,9 +212,9 @@ interface dataStore {
 }
 
 onMounted(() => {
-  ruleAttr();
-  regionLicenseRegion('0');//车牌地区
-  regionLicenseNumber('14');//车牌号
+    ruleAttr();
+    regionLicenseRegion('0');//车牌地区
+    regionLicenseNumber('14');//车牌号
 })
 
 const ruleAttr = () => {
@@ -245,7 +245,6 @@ const change = (value: any, title: title) => {
       })
       return val;
     });
-    // console.log(checkeddata.VehicleInformationlist)
   } else {
 
   }

+ 77 - 57
src/components/ruleConditionContainer/index.vue

@@ -34,27 +34,39 @@
             </el-select>
           </template>
           <template v-if="item.attrType == 'inputNumber'">
-            <template v-if="item.operator == '1' || item.operator == null">
-              <el-input-number v-model="item.min"></el-input-number>
-              <span style="margin: 0 10px ;">-</span>
-              <el-input-number v-model="item.max"></el-input-number>
-            </template>
-            <template v-if="item.operator == '2'">
-              <span><</span>
-              <el-input-number v-model="item.min"></el-input-number>
-            </template>
-            <template v-if="item.operator == '3'">
-              <span>≤</span>
-              <el-input-number v-model="item.min"></el-input-number>
-            </template>
-            <template v-if="item.operator == '4'">
-              <span>></span>
-              <el-input-number v-model="item.max"></el-input-number>
-            </template>
-            <template v-if="item.operator == '5'">
-              <span>≥</span>
-              <el-input-number v-model="item.max"></el-input-number>
-            </template>
+            <el-row class="flex a-c">
+              <template v-if="item.operator == '1' || item.operator == null">
+                <el-col :span="11">
+                  <el-input-number v-model="item.min" style="width: 100%;"></el-input-number>
+                </el-col>
+                <el-col :span="2">
+                  <div class="flex a-c j-c " style="font-size: 14px;color: #333;">至</div>
+                </el-col>
+                <el-col :span="11">
+                  <el-input-number v-model="item.max" style="width: 100%;"></el-input-number>
+                </el-col>
+              </template>
+              <template v-if="item.operator == '2'">
+                <el-col :span="24">
+                  <el-input-number v-model="item.min" style="width: 100%;"></el-input-number>
+                </el-col>
+              </template>
+              <template v-if="item.operator == '3'">
+                <el-col :span="24">
+                  <el-input-number v-model="item.min" style="width: 100%;"></el-input-number>
+                </el-col>
+              </template>
+              <template v-if="item.operator == '4'">
+                <el-col :span="24">
+                  <el-input-number v-model="item.max" style="width: 100%;"></el-input-number>
+                </el-col>
+              </template>
+              <template v-if="item.operator == '5'">
+                <el-col :span="24">
+                  <el-input-number v-model="item.max" style="width: 100%;"></el-input-number>
+                </el-col>
+              </template>
+            </el-row>
           </template>
           <template v-if="item.attrType == 'select'">
             <el-select v-model="item.minArray" placeholder="选择值" clearable filterable multiple
@@ -66,46 +78,53 @@
           <template v-if="item.attrType == 'inputTag'">
             <el-input-tag v-model="item.minArray" @change="change($event, index)" placeholder="输入内容后按回车键隔开" />
           </template>
-
           <template v-if="item.attrType == 'datetime'">
-            <template v-if="item.operator == '1' || item.operator == null">
-              <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
-                value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 250px;">
-              </el-date-picker>
-              <span>~</span>
-              <el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
-                value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 250px;">
-              </el-date-picker>
-            </template>
-            <template v-if="item.operator == '2'">
-              <span><</span>
-              <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
-                value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 170px;">
-              </el-date-picker>
-            </template>
-            <template v-if="item.operator == '3'">
-              <span>≤</span>
-              <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
-                value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 170px;">
-              </el-date-picker>
-            </template>
-            <template v-if="item.operator == '4'">
-              <span>></span>
-              <el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
-                value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 170px;">
-              </el-date-picker>
-            </template>
-            <template v-if="item.operator == '5'">
-              <span>≥</span>
-              <el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
-                value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 170px;">
-              </el-date-picker>
-            </template>
+            <el-row class="flex a-c">
+              <template v-if="item.operator == '1' || item.operator == null">
+                <el-col :span="11">
+                  <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                    value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
+                  </el-date-picker>
+                </el-col>
+                <el-col :span="2">
+                  <div class="flex a-c j-c " style="font-size: 14px;color: #333;">至</div>
+                </el-col>
+                <el-col :span="11">
+                  <el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                    value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
+                  </el-date-picker>
+                </el-col>
+              </template>
+              <template v-if="item.operator == '2'">
+                <el-col :span="24">
+                  <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                    value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
+                  </el-date-picker>
+                </el-col>
+              </template>
+              <template v-if="item.operator == '3'">
+                <el-col :span="24"> <el-date-picker v-model="item.min" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                    value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
+                  </el-date-picker></el-col>
+              </template>
+              <template v-if="item.operator == '4'">
+                <el-col :span="24"><el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                    value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
+                  </el-date-picker></el-col>
+              </template>
+              <template v-if="item.operator == '5'">
+                <el-col :span="24"> <el-date-picker v-model="item.max" type="datetime" format="YYYY-MM-DD HH:mm:ss"
+                    value-format="YYYY-MM-DD HH:mm:ss" time-format="HH:mm:ss" placeholder="选择日期时间" style="width: 100%;">
+                  </el-date-picker></el-col>
+
+              </template>
+            </el-row>
+
           </template>
         </el-col>
         <el-col :span="1">
-          <el-icon color="#666" size="20" style="margin-left: 10px;" @click="attrDel(index)">
-            <CircleCloseFilled />
+          <el-icon color="#666" size="18" style="margin-left: 10px;" @click="attrDel(index)">
+            <Delete />
           </el-icon>
         </el-col>
       </el-row>
@@ -125,6 +144,7 @@ const attrDel = (index: number) => {
   console.log(index)
   emits('Del', index)
 }
+
 const change = (e: string[] | undefined, index: number) => {
   console.log(e)
   emits('selectChange', { e, index })

+ 0 - 1
src/router/guards.ts

@@ -89,7 +89,6 @@ function setupRoutes(router: Router) {
         }
         routeStore.setCurrentRemoveRoutes(removeRoutes)
         // 动态路由生成并注册后,重新进入当前路由
-        console.log(156789,localStorage.getItem("token"))
         if(localStorage.getItem("token")!=''){
           next({
             path: to.path,

+ 1 - 0
src/router/modules/externalAgreement.ts

@@ -29,6 +29,7 @@ const routes: RouteRecordRaw = {
             activeMenu: '/personnel/member',
           },
         },
+       
       ]
     },
     {

+ 9 - 0
src/types/auto-imports.d.ts

@@ -7,6 +7,7 @@
 export {}
 declare global {
   const EffectScope: typeof import('vue')['EffectScope']
+  const Fileonload: typeof import('../utils/composables/fileProcessing')['Fileonload']
   const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
   const computed: typeof import('vue')['computed']
   const convertToTreeData: typeof import('../utils/composables/routeUtils')['convertToTreeData']
@@ -16,16 +17,22 @@ declare global {
   const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
   const defineComponent: typeof import('vue')['defineComponent']
   const defineStore: typeof import('pinia')['defineStore']
+  const dictLists: typeof import('../utils/composables/dictService')['dictLists']
+  const dictionaryMatch: typeof import('../utils/composables/dictService')['dictionaryMatch']
+  const download: typeof import('../utils/composables/fileProcessing')['download']
   const effectScope: typeof import('vue')['effectScope']
+  const formatFileSize: typeof import('../utils/composables/fileProcessing')['formatFileSize']
   const getActivePinia: typeof import('pinia')['getActivePinia']
   const getCurrentInstance: typeof import('vue')['getCurrentInstance']
   const getCurrentScope: typeof import('vue')['getCurrentScope']
+  const getDict: typeof import('../utils/composables/dictService')['getDict']
   const h: typeof import('vue')['h']
   const inject: typeof import('vue')['inject']
   const isProxy: typeof import('vue')['isProxy']
   const isReactive: typeof import('vue')['isReactive']
   const isReadonly: typeof import('vue')['isReadonly']
   const isRef: typeof import('vue')['isRef']
+  const loadDicts: typeof import('../utils/composables/dictService')['loadDicts']
   const mapActions: typeof import('pinia')['mapActions']
   const mapGetters: typeof import('pinia')['mapGetters']
   const mapState: typeof import('pinia')['mapState']
@@ -51,10 +58,12 @@ declare global {
   const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
   const permissionDictionary: typeof import('../utils/composables/routeUtils')['permissionDictionary']
   const preprocessRoutes: typeof import('../utils/composables/routeUtils')['preprocessRoutes']
+  const processFileName: typeof import('../utils/composables/fileProcessing')['processFileName']
   const provide: typeof import('vue')['provide']
   const reactive: typeof import('vue')['reactive']
   const readonly: typeof import('vue')['readonly']
   const ref: typeof import('vue')['ref']
+  const removeUniqueIdentifier: typeof import('../utils/composables/fileProcessing')['removeUniqueIdentifier']
   const resolveComponent: typeof import('vue')['resolveComponent']
   const setActivePinia: typeof import('pinia')['setActivePinia']
   const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']

+ 1 - 0
src/types/components.d.ts

@@ -10,6 +10,7 @@ declare module 'vue' {
     Auth: typeof import('./../components/Auth/index.vue')['default']
     ComplexTable: typeof import('./../components/complexTable/index.vue')['default']
     DialogSetDeptLeader: typeof import('./../components/DialogSetDeptLeader/index.vue')['default']
+    Empty: typeof import('./../components/empty/index.vue')['default']
     FileUpload: typeof import('./../components/FileUpload/index.vue')['default']
     FixedActionBar: typeof import('./../components/FixedActionBar/index.vue')['default']
     HButton: typeof import('./../layouts/ui-kit/HButton.vue')['default']