Browse Source

字段校验,拖拽...

wangwei 4 years ago
parent
commit
d1595ba6b4

+ 1 - 0
src/api/sys/model/userModel.ts

@@ -89,6 +89,7 @@ export interface CommonTreeModel {
  */
 export interface getGroupTreeModel {
   count: number;
+  tree: object[];
 }
 /**
  * @description: Get user information return value

+ 2 - 1
src/api/sys/user.ts

@@ -6,6 +6,7 @@ import {
   getUserListParams,
   GetUserInfoByUserIdModel,
   CommonRowModel,
+  getGroupTreeModel,
   CommonTreeModel,
   AddUserParams,
   DeleteUserParams,
@@ -181,7 +182,7 @@ export function getRuleById(params: RuleIdParams) {
 }
 //请求允许访问的规则 params 角色组pid
 export function getAllowRule(params: RuleIdParams) {
-  return defHttp.request<CommonTreeModel>({
+  return defHttp.request<getGroupTreeModel>({
     url: Api.MenuUrl + params.id,
     method: 'GET',
   });

+ 2 - 1
src/components/Form/src/components/FormAction.vue

@@ -111,7 +111,8 @@
       const getSubmitBtnOptions = computed(() => {
         return Object.assign(
           {
-            text: t('common.queryText'),
+            // text: t('common.queryText'),
+            text: t('common.submitText'),
           },
           props.submitButtonOptions
         );

+ 3 - 0
src/components/Form/src/hooks/useFormEvents.ts

@@ -237,10 +237,13 @@ export function useFormEvents({
     const formEl = unref(formElRef);
     if (!formEl) return;
     try {
+      console.log('===========try=========');
       const values = await validate();
+      console.log(`values`, values);
       const res = handleFormValues(values);
       emit('submit', res);
     } catch (error) {
+      console.log(`error`, error);
       throw new Error(error);
     }
   }

+ 0 - 4
src/components/Table/src/BasicTable.vue

@@ -295,8 +295,6 @@
 
       emit('register', tableAction, formActions);
 
-      console.log('===============分割线=============');
-
       // 初始化 sortable 实现拖动
       function initSortable() {
         const el = document.querySelector('.mytable tbody') as any;
@@ -333,14 +331,12 @@
         });
       }
       onMounted(() => {
-        console.log('props.canDragRow', props.canDragRow);
         if (!props.canDragRow) {
           return;
         }
         initSortable(); // 开启拖拽功能
         // console.log(`fn`, fn)
       });
-      console.log('===============分割线=============');
       return {
         tableElRef,
         getBindValues,

+ 3 - 0
src/utils/adapt.ts

@@ -3,6 +3,7 @@
 interface AdaptWidth {
   elContainer: number;
   labelWidth: number;
+  tableHeight: number;
 }
 
 export function adapt() {
@@ -11,9 +12,11 @@ export function adapt() {
   if (clientWidth > 1000) {
     adaptWidth.elContainer = 20;
     adaptWidth.labelWidth = 110;
+    adaptWidth.tableHeight = 600;
   } else {
     adaptWidth.elContainer = 22;
     adaptWidth.labelWidth = 80;
+    adaptWidth.tableHeight = 350;
   }
   return adaptWidth;
 }

+ 65 - 12
src/views/conventional/system/components/ArrayCom.vue

@@ -5,35 +5,87 @@
       <div class="name-head">键名</div>
       <div class="value-head">键值</div>
     </div>
-    <div class="content" v-for="(item, i) in list" :key="i">
-      <div class="name-content">
-        <Input />
+    <div class="array-item">
+      <div class="content-item" v-for="(item, index) in list" :key="index">
+        <div class="name-content">
+          <Input v-model:value="item.name" />
+        </div>
+        <div class="value-content">
+          <Input v-model:value="item.value" />
+        </div>
+        <a-button class="mr-2" preIcon="mdi:close-thick" type="danger" @click="remove(index)" />
+        <a-button class="mr-2 drag-btn" preIcon="ri:drag-move-2-fill" type="primary" />
       </div>
-      <div class="value-content">
-        <Input :value="item.value" />
-      </div>
-      <a-button preIcon="mdi:close-thick" type="danger" class="mr-2" />
     </div>
-    <a-button @click="create" class="add-btn mr-2" type="success"> 追加 </a-button>
+    <a-button class="add-btn mr-2" size="small" type="success" @click="create"> 追加 </a-button>
   </div>
 </template>
 <script lang="ts">
-  import { defineComponent, reactive, toRefs } from 'vue';
+  import { defineComponent, onMounted, reactive, toRefs } from 'vue';
   import { Input } from 'ant-design-vue';
+  import Sortable from 'sortablejs';
 
   export default defineComponent({
     components: { Input },
     setup() {
       const state = reactive({
-        list: [{ name: '' }],
+        list: [
+          { name: '12df', value: 'hello' },
+          { name: 'sdfa33', value: 'dfds33' },
+        ] as object[],
+      });
+
+      // 初始化 sortable 实现拖动
+      function initSortable() {
+        console.log('===========init----dfsadf=======');
+        console.log(`document`, document);
+        const el = document.querySelector('.array-item') as any;
+        console.log(el);
+        Sortable.create(el, {
+          handle: '.drag-btn',
+          sort: true, // boolean 定义是否列表单元是否可以在列表容器内进行拖拽排序
+          delay: 0, // number 定义鼠标选中列表单元可以开始拖动的延迟时间;
+          touchStartThreshold: 0, // px, how many pixels the point should move before cancelling a delayed drag event
+          disabled: false, // boolean 定义是否此sortable对象是否可用,为true时sortable对象不能拖放排序等功能,为false时为可以进行排序,相当于一个开关;
+          animation: 150, // ms, number 单位:ms,定义排序动画的时间
+          easing: 'cubic-bezier(1, 0, 0, 1)', // Easing for animation. Defaults to null. See https://easings.net/ for examples.
+          ghostClass: 'drag-ghost', // drop placeholder的css类名
+          draggable: '.content-item', // 允许拖拽的项目类名
+          chosenClass: 'sortable-chosen', // 被选中项的css 类名
+          dragClass: 'sortable-drag', // 正在被拖拽中的css类名
+          group: { name: 'name', pull: true, put: true },
+
+          // 拖拽完成
+          onUpdate: function (evt) {
+            console.log(evt);
+            console.log(`移动前的位置索引`, evt.oldIndex);
+            console.log(`移动后的位置索引`, evt.newIndex);
+            const newIndex = evt.newIndex as number;
+            const oldIndex = evt.oldIndex as number;
+            const temp = state.list[oldIndex];
+            state.list[oldIndex] = state.list[newIndex];
+            state.list[newIndex] = temp;
+            console.log(`list`, state.list);
+          },
+        });
+      }
+      onMounted(() => {
+        initSortable(); // 开启拖拽功能
+        // console.log(`fn`, fn)
       });
 
       function create() {
+        console.log(`state.list`, state.list);
         state.list.push({ name: '' });
       }
+      function remove(i) {
+        console.log(`i`, i);
+        state.list.splice(i, 1);
+      }
 
       return {
         create,
+        remove,
         ...toRefs(state),
       };
     },
@@ -41,7 +93,7 @@
 </script>
 <style scoped>
   .wrap {
-    width: 60%;
+    width: 55%;
   }
 
   .head {
@@ -60,7 +112,7 @@
     font-weight: bold;
   }
 
-  .content {
+  .content-item {
     display: flex;
     margin: 5px 0;
   }
@@ -76,6 +128,7 @@
   }
 
   .add-btn {
+    margin-top: 2px;
     color: #fff;
   }
 </style>

+ 1 - 1
src/views/conventional/system/components/Checkbox.vue

@@ -57,7 +57,7 @@
   }
 
   .checkbox {
-    width: 65%;
+    width: 55%;
     margin-right: 10px;
   }
 

+ 1 - 1
src/views/conventional/system/components/DatePicker.vue

@@ -56,7 +56,7 @@
   }
 
   .date-picker {
-    width: 65%;
+    width: 55%;
     margin-right: 10px;
   }
 

+ 19 - 8
src/views/conventional/system/components/Input.vue

@@ -1,18 +1,20 @@
 <template>
   <div class="wrap">
-    <Input :type="type" :value="value" @focus="onFocus" @change="onChange" @blur="onBlur" />
+    <Input :value="value" @focus="onFocus" @change="onChange" @blur="onBlur" />
     <span>{{ reactData.tip }}</span>
-    <span class="errorMsg">{{ reactData.error }}</span>
+    <span class="error-msg">{{ reactData.error }}</span>
   </div>
 </template>
 <script lang="ts">
   import { Input } from 'ant-design-vue';
-  import { defineComponent, reactive, toRefs } from 'vue';
+  import { defineComponent, reactive, toRefs, watch } from 'vue';
+  import { validateType } from '../validTools';
 
   const props = {
     value: { type: String, default: '' },
     tip: { type: String, default: '' },
-    type: { type: String, default: '' },
+    errMsg: { type: String, default: '' },
+    rules: { type: Array, default: [] },
   };
 
   export default defineComponent({
@@ -24,14 +26,23 @@
         tip: '',
         error: '',
       });
+      watch(
+        () => props.errMsg,
+        (errMsg) => {
+          reactData.error = errMsg;
+        }
+      );
       function onFocus() {
         reactData.tip = props.tip;
         reactData.error = '';
       }
       function onBlur(e) {
         reactData.tip = '';
-        console.log(`e`, e.target.value);
-        reactData.error = '错误dsfsdafsad';
+        if (props.rules && props.rules[0]) {
+          const res = validateType(props.rules, e.target.value);
+          console.log(`res`, res);
+          reactData.error = res.errMsg;
+        }
       }
 
       function onChange(e) {
@@ -53,7 +64,7 @@
   }
 
   input {
-    width: 60%;
+    width: 55%;
     margin-right: 10px;
   }
 
@@ -63,7 +74,7 @@
     color: gray;
   }
 
-  .errorMsg {
+  .error-msg {
     color: red;
   }
 </style>

+ 24 - 3
src/views/conventional/system/components/InputNumber.vue

@@ -10,15 +10,19 @@
       @blur="onBlur"
     />
     <span>{{ reactData.tip }}</span>
+    <span class="error-msg">{{ reactData.error }}</span>
   </div>
 </template>
 <script lang="ts">
   import { InputNumber } from 'ant-design-vue';
-  import { defineComponent, reactive, toRefs } from 'vue';
+  import { defineComponent, reactive, toRefs, watch } from 'vue';
+  import { validateType } from '../validTools';
 
   const props = {
     value: { type: Number, default: 0 },
     tip: { type: String, default: '' },
+    rules: { type: Array, default: [] },
+    errMsg: { type: String, default: '' },
   };
 
   export default defineComponent({
@@ -28,12 +32,25 @@
     setup(props, { emit }) {
       const reactData = reactive({
         tip: '',
+        error: '',
       });
+      watch(
+        () => props.errMsg,
+        (errMsg) => {
+          reactData.error = errMsg;
+        }
+      );
       function onFocus() {
+        reactData.error = '';
         reactData.tip = props.tip;
       }
-      function onBlur() {
+      function onBlur(e) {
         reactData.tip = '';
+        if (props.rules && props.rules[0]) {
+          const res = validateType(props.rules, e.target.value);
+          console.log(`res`, res);
+          reactData.error = res.errMsg;
+        }
       }
 
       function onChange(val) {
@@ -55,7 +72,7 @@
   }
 
   .input-number {
-    width: 65%;
+    width: 55%;
     margin-right: 10px;
   }
 
@@ -64,4 +81,8 @@
     line-height: 250%;
     color: gray;
   }
+
+  .error-msg {
+    color: red;
+  }
 </style>

+ 27 - 3
src/views/conventional/system/components/InputTextArea.vue

@@ -8,15 +8,19 @@
       @blur="onBlur"
     />
     <span>{{ reactData.tip }}</span>
+    <span class="error-msg">{{ reactData.error }}</span>
   </div>
 </template>
 <script lang="ts">
   import { Input } from 'ant-design-vue';
-  import { defineComponent, reactive, toRefs } from 'vue';
+  import { defineComponent, reactive, toRefs, watch } from 'vue';
+  import { validateType } from '../validTools';
 
   const props = {
     value: { type: String, default: '' },
     tip: { type: String, default: '' },
+    errMsg: { type: String, default: '' },
+    rules: { type: Array, default: [] },
   };
 
   export default defineComponent({
@@ -26,12 +30,28 @@
     setup(props, { emit }) {
       const reactData = reactive({
         tip: '',
+        error: '',
       });
+
+      watch(
+        () => props.errMsg,
+        (errMsg) => {
+          reactData.error = errMsg;
+        }
+      );
+
       function onFocus() {
+        reactData.error = '';
         reactData.tip = props.tip;
       }
-      function onBlur() {
+
+      function onBlur(e) {
         reactData.tip = '';
+        if (props.rules && props.rules[0]) {
+          const res = validateType(props.rules, e.target.value);
+          console.log(`res`, res);
+          reactData.error = res.errMsg;
+        }
       }
 
       function onChange(e) {
@@ -53,7 +73,7 @@
   }
 
   .input-text-area {
-    width: 65%;
+    width: 55%;
     margin-right: 10px;
   }
 
@@ -62,4 +82,8 @@
     line-height: 250%;
     color: gray;
   }
+
+  .error-msg {
+    color: red;
+  }
 </style>

+ 1 - 1
src/views/conventional/system/components/Radio.vue

@@ -56,7 +56,7 @@
   }
 
   .radio {
-    width: 65%;
+    width: 55%;
     margin-right: 10px;
   }
 

+ 1 - 1
src/views/conventional/system/components/Select.vue

@@ -57,7 +57,7 @@
   }
 
   .select {
-    width: 65%;
+    width: 55%;
     margin-right: 10px;
   }
 

+ 1 - 2
src/views/conventional/system/components/TimePicker.vue

@@ -36,7 +36,6 @@
       }
 
       function onChange(val) {
-        console.log(`val`, val);
         emit('change', val);
       }
       return {
@@ -56,7 +55,7 @@
   }
 
   .wrap-time .ant-time-picker {
-    width: 65%;
+    width: 55%;
     margin-right: 10px;
   }
 

+ 10 - 5
src/views/conventional/system/data.ts

@@ -3,6 +3,7 @@ import { FormSchema } from '/@/components/Form/index';
 import { h } from 'vue';
 import Input from './components/Input.vue';
 import InputTextArea from './components/InputTextArea.vue';
+import InputNumber from './components/InputNumber.vue';
 import ArrayCom from './components/ArrayCom.vue';
 import Select from './components/Select.vue';
 import Checkbox from './components/Checkbox.vue';
@@ -10,20 +11,19 @@ import Radio from './components/Radio.vue';
 import DatePicker from './components/DatePicker.vue';
 import TimePicker from './components/TimePicker.vue';
 import Switch from './components/Switch.vue';
-// import InputNumber from './InputNumber.vue';
 
 export const columns: BasicColumn[] = [
   {
     title: '变量标题',
     align: 'left',
     dataIndex: 'title',
-    width: 130,
+    width: 100,
   },
   {
     title: '变量值',
     align: 'left',
     dataIndex: 'value',
-    width: 250,
+    width: 300,
     customRender: ({ record }) => {
       switch (record.type) {
         case 'Input':
@@ -34,6 +34,8 @@ export const columns: BasicColumn[] = [
           return h(Input, {
             value: record.value,
             tip: record.tip,
+            errMsg: record.errMsg || '',
+            rules: record.rules || [],
             style: { width: '100%' },
             onChange: onchange,
           });
@@ -41,10 +43,11 @@ export const columns: BasicColumn[] = [
           const onNumberChange = (val) => {
             record.value = val;
           };
-          return h(Input, {
+          return h(InputNumber, {
             value: record.value,
             tip: record.tip,
-            type: 'number',
+            errMsg: record.errMsg || '',
+            rules: record.rules || [],
             style: { width: '100%' },
             onChange: onNumberChange,
           });
@@ -100,6 +103,8 @@ export const columns: BasicColumn[] = [
           return h(InputTextArea, {
             value: record.value,
             tip: record.tip,
+            errMsg: record.errMsg || '',
+            rules: record.rules || [],
             style: { width: '100%' },
             onChange: onTextAreaChange,
           });

+ 61 - 13
src/views/conventional/system/index.vue

@@ -1,6 +1,6 @@
 <template>
   <CollapseContainer
-    class="container"
+    class="sys-container"
     title="系统配置"
     :canExpan="false"
     helpMessage="可以在此增改系统的变量和分组,也可以自定义分组和变量"
@@ -10,7 +10,6 @@
     <a-button type="default" class="mr-2" @click="onBasicConfig"> 字典配置 </a-button>
     <a-button type="default" class="mr-2" @click="onBasicConfig"> 会员配置 </a-button>
     <a-button
-      type="default"
       preIcon="bx:bx-plus-medical"
       @mouseenter="showTip"
       @mouseleave="hideTip"
@@ -18,24 +17,26 @@
       class="mr-2"
     />
     <span v-if="tipShow" class="tip">点击添加新的配置</span>
-    <BasicTable v-if="tableShow" @register="registerTable" />
-    <BasicForm v-if="formShow" @register="registerForm" />
-    <div class="actions">
+    <BasicTable ref="tableRef" :canResize="true" v-if="tableShow" @register="registerTable" />
+    <BasicForm class="config-form" v-if="formShow" @register="registerForm" />
+    <div v-if="tableShow" class="actions">
       <a-button class="mr-2" type="default" @click="onBasicConfig">
         {{ t('common.resetText') }}
       </a-button>
-      <a-button class="mr-2" type="primary" @click="onBasicConfig">
+      <a-button class="mr-2" type="primary" @click="onSubmit">
         {{ t('common.submitText') }}
       </a-button>
     </div>
   </CollapseContainer>
 </template>
 <script lang="ts">
-  import { defineComponent, reactive, toRefs } from 'vue';
+  import { defineComponent, reactive, ref, toRefs, unref } from 'vue';
   import { CollapseContainer } from '/@/components/Container/index';
   import { BasicForm, useForm } from '/@/components/Form/index';
   import { schemas } from './data';
   import { useI18n } from '/@/hooks/web/useI18n';
+  import { adapt } from '/@/utils/adapt';
+  import { validateType } from './validTools';
   import {
     BasicTable,
     useTable,
@@ -43,7 +44,7 @@
     // BasicColumn,
     // ActionItem,
     // EditRecordRow,
-    // TableActionType,
+    TableActionType,
   } from '/@/components/Table';
   import { columns } from './data';
 
@@ -51,13 +52,16 @@
     components: { CollapseContainer, BasicTable, BasicForm },
     setup() {
       const { t } = useI18n();
+      const tableHeight = adapt().tableHeight;
       const state = reactive({
         tipShow: false,
         tableShow: true,
         formShow: false,
       });
+      const tableRef = ref<Nullable<TableActionType>>(null);
       const [registerTable] = useTable({
         columns: columns,
+        maxHeight: tableHeight,
         dataSource: [
           {
             title: 'helloWorld',
@@ -65,8 +69,16 @@
             value: 'helloWorld',
             type: 'Input',
             tip: '我是helloworld字段的提示',
+            rules: [],
+          },
+          {
+            title: 'test',
+            name: 'test',
+            value: 'test',
+            type: 'Input',
+            tip: '我是test字段的提示',
+            rules: ['require', 'url'],
           },
-          { title: 'test', name: 'test', value: 'test', type: 'Input', tip: '我是test字段的提示' },
           {
             title: 'hello1',
             name: 'hello1',
@@ -122,9 +134,10 @@
           {
             title: 'hello3',
             name: 'hello3',
-            value: '10',
+            value: 10,
             type: 'InputNumber',
             tip: '我是test字段的提示',
+            rules: ['require', 'qq'],
           },
           {
             title: 'hello4',
@@ -132,6 +145,7 @@
             value: 'InputTextAreasdafasdf',
             type: 'InputTextArea',
             tip: '我是InputTextArea字段的提示123456789112',
+            rules: ['require', 'email'],
           },
           {
             title: 'hello4',
@@ -159,9 +173,18 @@
         actionColOptions: {
           span: 24,
         },
-        showActionButtonGroup: false,
+        showActionButtonGroup: true,
       });
 
+      function getTableAction() {
+        // 获取组件
+        const tableAction = unref(tableRef);
+        if (!tableAction) {
+          throw new Error('tableAction is null');
+        }
+        return tableAction;
+      }
+
       function showTip() {
         state.tipShow = true;
       }
@@ -174,29 +197,50 @@
         state.tableShow = true;
         state.formShow = false;
       }
+
       function addConfig() {
         state.tableShow = false;
         state.formShow = true;
       }
+
+      function onSubmit() {
+        console.log('==========onSubmit=========');
+        const data = getTableAction().getDataSource();
+        let flag = true;
+        data.map((item) => {
+          if (item.rules && item.rules.length) {
+            console.log(`item`, item.rules);
+            const res = validateType(item.rules, item.value);
+            item.errMsg = res.errMsg;
+            flag = res.isValid;
+          }
+        });
+        if (flag) {
+          console.log('=======全部校验通过========');
+        }
+      }
       return {
         t,
+        tableRef,
         registerTable,
         registerForm,
         showTip,
         hideTip,
         onBasicConfig,
         addConfig,
+        onSubmit,
         ...toRefs(state),
       };
     },
   });
 </script>
 <style>
-  .container {
+  .sys-container {
     position: relative;
   }
 
-  .mr-2 {
+  .vben-collapse-container__body > .mr-2 {
+    margin-top: 5px;
     font-weight: 550 !important;
   }
 
@@ -209,6 +253,10 @@
     border-radius: 3px;
   }
 
+  .config-form {
+    margin-top: 10px;
+  }
+
   .ant-form-item-children {
     display: flex;
     justify-content: center;

+ 18 - 19
src/views/conventional/system/validTools.ts

@@ -15,13 +15,13 @@ const regexEnum = {
   // 0)
   email: '^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$', // 邮件
   color: '^[a-fA-F0-9]{6}$', // 颜色
-  url: '^http[s]?:\\/\\/([\\w-]+\\.)+[\\w-]+([\\w-./?%&=]*)?$', // url
+  url: '(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]', // url
   chinese: '^[\\u4E00-\\u9FA5\\uF900-\\uFA2D]+$', // 仅中文
   ascii: '^[\\x00-\\xFF]+$', // 仅ACSII字符
   zipcode: '^\\d{6}$', // 邮编
   mobile: '^(13|15|18|14)[0-9]{9}$', // 手机
   ip4: '^(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)\\.(25[0-5]|2[0-4]\\d|[0-1]\\d{2}|[1-9]?\\d)$', // ip地址
-  notempty: '^\\S+$', // 非空
+  require: '^\\S+$', // 非空
   picture: '(.*)\\.(jpg|bmp|gif|ico|pcx|jpeg|tif|png|raw|tga)$', // 图片
   jpg: '(.*)\\.(jpg|gif)$', // 图片
   rar: '(.*)\\.(rar|zip|7zip|tgz)$', // 压缩文件
@@ -40,41 +40,40 @@ const regexEnum = {
   uploadFile: '(.*)\\.(jpg|bmp|gif|png|jpeg|tif|pdf|doc|docx|xls|xlsx|ppt|pptx)$', // 图片
 };
 const errMsg = {
-  require: '请输入内容',
+  require: '必填',
   digits: '请填写数字',
   letters: '请填写字母',
   date: '日期格式错误:YYYY-MM-DD',
   time: '时间格式错误:HH:mm:ss',
-  emial: '请输入正确的邮箱',
+  email: '请输入正确的邮箱',
   url: '请输入正确的网址',
   qq: '请输入正确的QQ号码',
   IDcard: '请输入正确的身份证号码',
   mobile: '请输入正确的手机号码',
   tel: '请输入正确的座机号码',
   zipcode: '请输入正确的邮编号码',
-  passworld: '请输入6-18位长度的密码(数字、英文、特殊符号且必须包含数字及英文)',
-  chinese: '请输入中文(不包含其他字符)',
-  username: '请输入匹配由数字、26个英文字母或下划线组成的字符串',
+  password: '6-18位且必须包含数字及英文',
+  chinese: '请输入汉字(不包含其他字符)',
+  username: '数字、26个英文字母或下划线',
 };
 
-const res = { isValid: true, errMsg: '' };
+interface Res {
+  isValid: boolean;
+  errMsg: string;
+}
+
+const res: Res = { isValid: true, errMsg: '' };
+
 export const validateType = (rules, val) => {
   const isValid = rules.every((item) => {
     const reg = new RegExp(regexEnum[item]);
+    console.log(`reg`, reg);
     res.errMsg = errMsg[item];
     return reg.test(val);
   });
-
   res.isValid = isValid;
+  if (isValid) {
+    res.errMsg = '';
+  }
   return res;
-  // rules.map((item) => {
-  //   if (!res.isValid) {
-  //     return;
-  //   }
-  //   const reg = new RegExp(regexEnum[item]);
-  //   if (!reg.test(val)) {
-  //     res.isValid = false;
-  //     res.errMsg = errMsg[item];
-  //   }
-  // });
 };

+ 21 - 9
src/views/permission/admin/index.vue

@@ -1,5 +1,10 @@
 <template>
-  <div>
+  <CollapseContainer
+    class="sys-container"
+    title="管理员管理"
+    :canExpan="false"
+    helpMessage="一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成"
+  >
     <BasicTable
       ref="tableRef"
       @register="registerTable"
@@ -27,10 +32,11 @@
     </BasicTable>
     <ExpExcelModel @register="register" @success="defaultHeader" />
     <Popup @register="addRegister" :popupData="popupData" @saveData="saveData" />
-  </div>
+  </CollapseContainer>
 </template>
 <script lang="ts">
-  import { defineComponent, onMounted, reactive, ref, toRefs, unref } from 'vue';
+  import { defineComponent, reactive, ref, toRefs, unref } from 'vue';
+  import { CollapseContainer } from '/@/components/Container/index';
   import Popup from './popup.vue';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { useModal } from '/@/components/Modal';
@@ -63,7 +69,7 @@
   }
 
   export default defineComponent({
-    components: { BasicTable, TableAction, Popup, ExpExcelModel },
+    components: { CollapseContainer, BasicTable, TableAction, Popup, ExpExcelModel },
     setup() {
       init();
       const { createMessage } = useMessage();
@@ -78,8 +84,8 @@
         disable_btn: true,
       });
       const [registerTable] = useTable({
-        title: '管理员管理',
-        titleHelpMessage: '一个管理员可以有多个角色组,左侧的菜单根据管理员所拥有的权限进行生成',
+        // title: '',
+        // titleHelpMessage: '',
         rowSelection: { type: 'checkbox' },
         columns: columns,
         // clickToRowSelect: false, // 点击行不勾选
@@ -294,9 +300,6 @@
           },
         ];
       }
-      onMounted(() => {
-        console.log(getTableAction());
-      });
       return {
         popupData,
         tableRef,
@@ -322,4 +325,13 @@
   .ant-calendar-picker {
     width: 100%;
   }
+  @media (max-width: 639px) {
+    .sys-container .vben-basic-table-header__toolbar > * {
+      margin-right: 3px;
+    }
+
+    .sys-container .vben-basic-table .ant-table-wrapper {
+      padding: 3px;
+    }
+  }
 </style>

+ 11 - 6
src/views/permission/admin_log/index.vue

@@ -1,6 +1,10 @@
 <template>
-  <div>
-    <BasicTable ref="tableRef" @register="registerTable" rowKey="id" @rowDbClick="handleDetail">
+  <CollapseContainer
+    class="sys-container"
+    title="管理员日志"
+    :canExpan="false"
+    helpMessage="管理员可以查看自己所拥有的权限的管理员日志"
+    ><BasicTable ref="tableRef" @register="registerTable" rowKey="id" @rowDbClick="handleDetail">
       <template #toolbar>
         <a-button type="danger" @click="deleteA"> 删除 </a-button>
         <a-button type="primary" @click="openModal"> 导出 </a-button>
@@ -11,10 +15,11 @@
     </BasicTable>
     <ExpExcelModel @register="register" @success="defaultHeader" />
     <Popup @register="PopupRegister" :popupData="popupData" />
-  </div>
+  </CollapseContainer>
 </template>
 <script lang="ts">
   import { defineComponent, reactive, ref, unref } from 'vue';
+  import { CollapseContainer } from '/@/components/Container/index';
   import Popup from './popup.vue';
   import { getUserList, deleteUser } from '/@/api/sys/user';
   import { useModal } from '/@/components/Modal';
@@ -62,7 +67,7 @@
   ];
 
   export default defineComponent({
-    components: { BasicTable, TableAction, Popup, ExpExcelModel },
+    components: { CollapseContainer, BasicTable, TableAction, Popup, ExpExcelModel },
     setup() {
       const tableRef = ref<Nullable<TableActionType>>(null);
       const currentEditKeyRef = ref('');
@@ -72,8 +77,8 @@
       const { refreshMenu } = usePermission();
       const [register, { openModal }] = useModal();
       const [registerTable] = useTable({
-        title: '管理员日志',
-        titleHelpMessage: '管理员可以查看自己所拥有的权限的管理员日志',
+        // title: '管理员日志',
+        // titleHelpMessage: '',
         rowSelection: { type: 'checkbox' },
         columns: columns,
         clickToRowSelect: false, // 点击行不勾选

+ 12 - 6
src/views/permission/group/index.vue

@@ -1,5 +1,10 @@
 <template>
-  <div>
+  <CollapseContainer
+    class="sys-container"
+    title="角色组"
+    :canExpan="false"
+    helpMessage="角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别的下级角色组或管理员"
+  >
     <BasicTable
       ref="tableRef"
       @register="registerTable"
@@ -22,10 +27,11 @@
     </BasicTable>
     <ExpExcelModel @register="register" @success="defaultHeader" />
     <Popup @register="addRegister" :popupData="popupData" @saveData="saveData" />
-  </div>
+  </CollapseContainer>
 </template>
 <script lang="ts">
   import { defineComponent, reactive, ref, toRefs, unref, nextTick } from 'vue';
+  import { CollapseContainer } from '/@/components/Container/index';
   import Popup from './popup.vue';
   import { useModal } from '/@/components/Modal';
   //   import { getAllMenuList } from '/@/api/sys/menu';
@@ -64,7 +70,7 @@
   // }
 
   export default defineComponent({
-    components: { BasicTable, TableAction, Popup, ExpExcelModel },
+    components: { CollapseContainer, BasicTable, TableAction, Popup, ExpExcelModel },
     setup() {
       // const userStore = useUserStore();
       const { createMessage } = useMessage();
@@ -83,9 +89,9 @@
         disable_btn: true,
       });
       const [registerTable, { expandAll, collapseAll }] = useTable({
-        title: '角色列表',
-        titleHelpMessage:
-          '角色组可以有多个,角色有上下级层级关系,如果子角色有角色组和管理员的权限则可以派生属于自己组别的下级角色组或管理员',
+        // title: '角色列表',
+        // titleHelpMessage:
+        //   '',
         rowSelection: { type: 'checkbox' },
         columns: columns,
         // clickToRowSelect: false, // 点击行不勾选

+ 12 - 6
src/views/permission/rule/index.vue

@@ -1,5 +1,10 @@
 <template>
-  <div>
+  <CollapseContainer
+    class="sys-container"
+    title="菜单规则"
+    :canExpan="false"
+    helpMessage="规则通常对应一个控制器的方法,同时左侧的菜单栏数据也从规则中体现,通常建议通过命令行进行生成规则节点"
+  >
     <BasicTable
       ref="tableRef"
       @register="registerTable"
@@ -23,10 +28,11 @@
     </BasicTable>
     <ExpExcelModel @register="register" @success="defaultHeader" />
     <Popup @register="addRegister" :popupData="popupData" @saveData="saveData" />
-  </div>
+  </CollapseContainer>
 </template>
 <script lang="ts">
   import { defineComponent, reactive, ref, toRefs, unref, nextTick } from 'vue';
+  import { CollapseContainer } from '/@/components/Container/index';
   import Popup from './popup.vue';
   import { useModal } from '/@/components/Modal';
   import { useMessage } from '/@/hooks/web/useMessage';
@@ -54,7 +60,7 @@
   }
 
   export default defineComponent({
-    components: { BasicTable, TableAction, Popup, ExpExcelModel },
+    components: { CollapseContainer, BasicTable, TableAction, Popup, ExpExcelModel },
     setup() {
       const { createMessage } = useMessage();
       const { success /*, error */ } = createMessage;
@@ -70,9 +76,9 @@
         disable_btn: true,
       });
       const [registerTable, { expandAll, collapseAll }] = useTable({
-        title: '菜单规则',
-        titleHelpMessage:
-          '规则通常对应一个控制器的方法,同时左侧的菜单栏数据也从规则中体现,通常建议通过命令行进行生成规则节点',
+        // title: '菜单规则',
+        // titleHelpMessage:
+        //   '',
         rowSelection: { type: 'checkbox' },
         columns: columns,
         // clickToRowSelect: false, // 点击行不勾选