Explorar el Código

Merge branch 'master' of https://gitee.com/yudaocode/yudao-ui-admin-vue3 into dev

 Conflicts:
	src/views/infra/fileConfig/fileConfig.data.ts
	src/views/system/sms/smsChannel/sms.channel.data.ts
YunaiV hace 2 años
padre
commit
d73b8431a1

+ 6 - 11
src/api/system/notice/index.ts

@@ -1,7 +1,7 @@
 import request from '@/config/axios'
 
 export interface NoticeVO {
-  id: number
+  id: number | undefined
   title: string
   type: number
   content: string
@@ -11,32 +11,27 @@ export interface NoticeVO {
   createTime: Date
 }
 
-export interface NoticePageReqVO extends PageParam {
-  title?: string
-  status?: number
-}
-
 // 查询公告列表
-export const getNoticePageApi = (params: NoticePageReqVO) => {
+export const getNoticePage = (params: PageParam) => {
   return request.get({ url: '/system/notice/page', params })
 }
 
 // 查询公告详情
-export const getNoticeApi = (id: number) => {
+export const getNotice = (id: number) => {
   return request.get({ url: '/system/notice/get?id=' + id })
 }
 
 // 新增公告
-export const createNoticeApi = (data: NoticeVO) => {
+export const createNotice = (data: NoticeVO) => {
   return request.post({ url: '/system/notice/create', data })
 }
 
 // 修改公告
-export const updateNoticeApi = (data: NoticeVO) => {
+export const updateNotice = (data: NoticeVO) => {
   return request.put({ url: '/system/notice/update', data })
 }
 
 // 删除公告
-export const deleteNoticeApi = (id: number) => {
+export const deleteNotice = (id: number) => {
   return request.delete({ url: '/system/notice/delete?id=' + id })
 }

+ 1 - 1
src/api/system/sms/smsLog/index.ts

@@ -53,5 +53,5 @@ export const getSmsLogPageApi = (params: SmsLogPageReqVO) => {
 
 // 导出短信日志
 export const exportSmsLogApi = (params: SmsLogExportReqVO) => {
-  return request.download({ url: '/system/sms-log/export', params })
+  return request.download({ url: '/system/sms-log/export-excel', params })
 }

+ 8 - 3
src/components/Icon/src/IconSelect.vue

@@ -45,17 +45,22 @@ const tabsList = [
 const pageList = computed(() => {
   if (currentPage.value === 1) {
     return copyIconList[currentActiveType.value]
-      .filter((v) => v.includes(filterValue.value))
+      ?.filter((v) => v.includes(filterValue.value))
       .slice(currentPage.value - 1, pageSize.value)
   } else {
     return copyIconList[currentActiveType.value]
-      .filter((v) => v.includes(filterValue.value))
+      ?.filter((v) => v.includes(filterValue.value))
       .slice(
         pageSize.value * (currentPage.value - 1),
         pageSize.value * (currentPage.value - 1) + pageSize.value
       )
   }
 })
+const iconCount = computed(() => {
+  return copyIconList[currentActiveType.value] == undefined
+    ? 0
+    : copyIconList[currentActiveType.value].length
+})
 
 const iconItemStyle = computed((): ParameterCSSProperties => {
   return (item) => {
@@ -159,7 +164,7 @@ watch(
 
           <ElPagination
             small
-            :total="copyIconList[currentActiveType].length as unknown as number"
+            :total="iconCount"
             :page-size="pageSize"
             :current-page="currentPage"
             background

+ 1 - 1
src/components/XTable/src/XTable.vue

@@ -128,7 +128,7 @@ const getColumnsConfig = (options: XTableProps) => {
     proxyForm = true
     options.formConfig = {
       enabled: true,
-      titleWidth: 100,
+      titleWidth: 180,
       titleAlign: 'right',
       items: allSchemas.searchSchema
     }

+ 1 - 1
src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="my-process-designer">
-    <div class="my-process-designer__header">
+    <div class="my-process-designer__header" style="display: table-row-group; z-index: 999">
       <slot name="control-header"></slot>
       <template v-if="!$slots['control-header']">
         <ElButtonGroup key="file-control">

+ 0 - 2
src/components/bpmnProcessDesigner/package/penal/multi-instance/ElementMultiInstance.vue

@@ -3,10 +3,8 @@
     <el-form label-width="90px">
       <el-form-item label="回路特性">
         <el-select v-model="loopCharacteristics" @change="changeLoopCharacteristicsType">
-          <!--bpmn:MultiInstanceLoopCharacteristics-->
           <el-option label="并行多重事件" value="ParallelMultiInstance" />
           <el-option label="时序多重事件" value="SequentialMultiInstance" />
-          <!--bpmn:StandardLoopCharacteristics-->
           <el-option label="循环事件" value="StandardLoop" />
           <el-option label="无" value="Null" />
         </el-select>

+ 1 - 1
src/permission.ts

@@ -35,7 +35,7 @@ router.beforeEach(async (to, from, next) => {
       const userStore = useUserStoreWithOut()
       const permissionStore = usePermissionStoreWithOut()
       if (!dictStore.getIsSetDict) {
-        dictStore.setDictMap()
+        await dictStore.setDictMap()
       }
       if (!userStore.getIsSetUser) {
         isRelogin.show = true

+ 45 - 0
src/utils/permission.ts

@@ -0,0 +1,45 @@
+import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
+
+const { t } = useI18n() // 国际化
+
+/**
+ * 字符权限校验
+ * @param {Array} value 校验值
+ * @returns {Boolean}
+ */
+export function checkPermi(value: string[]) {
+  if (value && value instanceof Array && value.length > 0) {
+    const { wsCache } = useCache()
+    const permissionDatas = value
+    const all_permission = '*:*:*'
+    const permissions = wsCache.get(CACHE_KEY.USER).permissions
+    const hasPermission = permissions.some((permission) => {
+      return all_permission === permission || permissionDatas.includes(permission)
+    })
+    return !!hasPermission
+  } else {
+    console.error(t('permission.hasPermission'))
+    return false
+  }
+}
+
+/**
+ * 角色权限校验
+ * @param {string[]} value 校验值
+ * @returns {Boolean}
+ */
+export function checkRole(value: string[]) {
+  if (value && value instanceof Array && value.length > 0) {
+    const { wsCache } = useCache()
+    const permissionRoles = value
+    const super_admin = 'admin'
+    const roles = wsCache.get(CACHE_KEY.USER).roles
+    const hasRole = roles.some((role) => {
+      return super_admin === role || permissionRoles.includes(role)
+    })
+    return !!hasRole
+  } else {
+    console.error(t('permission.hasRole'))
+    return false
+  }
+}

+ 1 - 1
src/views/bpm/form/form.data.ts

@@ -10,7 +10,7 @@ export const rules = reactive({
 // CrudSchema
 const crudSchemas = reactive<VxeCrudSchema>({
   primaryKey: 'id',
-  primaryType: 'seq',
+  primaryType: 'id',
   primaryTitle: '表单编号',
   action: true,
   columns: [

+ 1 - 1
src/views/bpm/model/index.vue

@@ -250,7 +250,7 @@
           name="bpmnFile"
           :data="importForm"
         >
-          <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+          <Icon class="el-icon--upload" icon="ep:upload-filled" />
           <div class="el-upload__text"> 将文件拖到此处,或 <em>点击上传</em> </div>
           <template #tip>
             <div class="el-upload__tip" style="color: red">

+ 3 - 2
src/views/infra/apiAccessLog/apiAccessLog.data.ts

@@ -3,14 +3,15 @@ import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
 // CrudSchema
 const crudSchemas = reactive<VxeCrudSchema>({
   primaryKey: 'id',
-  primaryType: 'seq',
+  primaryType: 'id',
   primaryTitle: '日志编号',
   action: true,
   actionWidth: '80px',
   columns: [
     {
       title: '链路追踪',
-      field: 'traceId'
+      field: 'traceId',
+      isTable: false
     },
     {
       title: '用户编号',

+ 1 - 1
src/views/infra/apiErrorLog/apiErrorLog.data.ts

@@ -3,7 +3,7 @@ import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
 // CrudSchema
 const crudSchemas = reactive<VxeCrudSchema>({
   primaryKey: 'id',
-  primaryType: 'seq',
+  primaryType: 'id',
   primaryTitle: '日志编号',
   action: true,
   actionWidth: '300',

+ 9 - 7
src/views/infra/build/index.vue

@@ -8,7 +8,7 @@
           <el-button size="small" type="primary" @click="showJson">生成JSON</el-button>
           <el-button size="small" type="success" @click="showOption">生成Options</el-button>
           <el-button size="small" type="danger" @click="showTemplate">生成组件</el-button>
-          <el-button size="small" @click="changeLocale">中英切换</el-button>
+          <!-- <el-button size="small" @click="changeLocale">中英切换</el-button> -->
         </div>
       </el-col>
       <el-col>
@@ -19,9 +19,11 @@
       <div ref="editor" v-if="dialogVisible">
         <XTextButton style="float: right" :title="t('common.copy')" @click="copy(formValue)" />
         <el-scrollbar height="580">
-          <pre>
-            {{ formValue }}
-          </pre>
+          <div v-highlight>
+            <code class="hljs">
+              {{ formValue }}
+            </code>
+          </div>
         </el-scrollbar>
       </div>
       <span style="color: red" v-if="err">输入内容格式有误!</span>
@@ -69,9 +71,9 @@ const showTemplate = () => {
   type.value = 2
   formValue.value = makeTemplate()
 }
-const changeLocale = () => {
-  console.info('changeLocale')
-}
+// const changeLocale = () => {
+//   console.info('changeLocale')
+// }
 
 /** 复制 **/
 const copy = async (text: string) => {

+ 1 - 1
src/views/infra/job/JobLog.vue

@@ -70,7 +70,7 @@ const detailData = ref() // 详情 Ref
 // 详情操作
 const handleDetail = async (row: JobLogApi.JobLogVO) => {
   // 设置数据
-  const res = JobLogApi.getJobLogApi(row.id)
+  const res = await JobLogApi.getJobLogApi(row.id)
   detailData.value = res
   dialogTitle.value = t('action.detail')
   dialogVisible.value = true

+ 1 - 1
src/views/infra/job/job.data.ts

@@ -11,7 +11,7 @@ export const rules = reactive({
 // CrudSchema
 const crudSchemas = reactive<VxeCrudSchema>({
   primaryKey: 'id',
-  primaryType: 'seq',
+  primaryType: 'id',
   primaryTitle: '任务编号',
   action: true,
   actionWidth: '280px',

+ 1 - 1
src/views/infra/job/jobLog.data.ts

@@ -4,7 +4,7 @@ const { t } = useI18n()
 // CrudSchema
 const crudSchemas = reactive<VxeCrudSchema>({
   primaryKey: 'id',
-  primaryType: 'seq',
+  primaryType: 'id',
   primaryTitle: '日志编号',
   action: true,
   columns: [

+ 131 - 0
src/views/system/notice/form.vue

@@ -0,0 +1,131 @@
+<template>
+  <Dialog :title="modelTitle" v-model="modelVisible" width="800">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="80px"
+      v-loading="formLoading"
+    >
+      <el-form-item label="公告标题" prop="title">
+        <el-input v-model="formData.title" placeholder="请输入公告标题" />
+      </el-form-item>
+      <el-form-item label="公告内容" prop="content">
+        <Editor :model-value="formData.content" height="150px" />
+      </el-form-item>
+      <el-form-item label="公告类型" prop="type">
+        <el-select v-model="formData.type" placeholder="请选择公告类型" clearable>
+          <el-option
+            v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_NOTICE_TYPE)"
+            :key="parseInt(dict.value)"
+            :label="dict.label"
+            :value="parseInt(dict.value)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="状态" prop="status">
+        <el-select v-model="formData.status" placeholder="请选择状态" clearable>
+          <el-option
+            v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
+            :key="parseInt(dict.value)"
+            :label="dict.label"
+            :value="parseInt(dict.value)"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="formData.remark" type="textarea" placeholder="请输备注" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
+        <el-button @click="modelVisible = false">取 消</el-button>
+      </div>
+    </template>
+  </Dialog>
+</template>
+<script setup lang="ts">
+import { DICT_TYPE, getDictOptions } from '@/utils/dict'
+import * as NoticeApi from '@/api/system/notice'
+
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+
+const modelVisible = ref(false) // 弹窗的是否展示
+const modelTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+  id: undefined,
+  title: '',
+  type: undefined,
+  content: '',
+  status: undefined,
+  remark: ''
+})
+const formRules = reactive({
+  title: [{ required: true, message: '公告标题不能为空', trigger: 'blur' }],
+  type: [{ required: true, message: '公告类型不能为空', trigger: 'change' }],
+  status: [{ required: true, message: '状态不能为空', trigger: 'change' }],
+  content: [{ required: true, message: '公告内容不能为空', trigger: 'blur' }]
+})
+const formRef = ref() // 表单 Ref
+
+/** 打开弹窗 */
+const openModal = async (type: string, id?: number) => {
+  modelVisible.value = true
+  modelTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
+    formLoading.value = true
+    try {
+      formData.value = await NoticeApi.getNotice(id)
+    } finally {
+      formLoading.value = false
+    }
+  }
+}
+defineExpose({ openModal }) // 提供 openModal 方法,用于打开弹窗
+
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  if (!formRef) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as NoticeApi.NoticeVO
+    if (formType.value === 'create') {
+      await NoticeApi.createNotice(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await NoticeApi.updateNotice(data)
+      message.success(t('common.updateSuccess'))
+    }
+    modelVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
+  }
+}
+
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+    id: undefined,
+    title: '',
+    type: undefined,
+    content: '',
+    status: undefined,
+    remark: ''
+  }
+  formRef.value?.resetFields()
+}
+</script>

+ 130 - 121
src/views/system/notice/index.vue

@@ -1,150 +1,159 @@
 <template>
-  <ContentWrap>
-    <el-form ref="searchForm" :model="queryParms" :inline="true">
-      <el-form-item label="公告标题">
-        <el-input v-model="queryParms.title" />
+  <content-wrap>
+    <!-- 搜索工作栏 -->
+    <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+      <el-form-item label="公告标题" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入公告标题"
+          clearable
+          @keyup.enter="handleQuery"
+        />
       </el-form-item>
-      <el-form-item label="状态">
-        <el-select v-model="queryParms.status">
-          <el-option label="全部" value="" />
-          <el-option label="开启" :value="1" />
-          <el-option label="关闭" :value="0" />
+      <el-form-item label="公告状态" prop="status">
+        <el-select v-model="queryParams.status" placeholder="请选择公告状态" clearable>
+          <el-option
+            v-for="dict in getDictOptions(DICT_TYPE.COMMON_STATUS)"
+            :key="parseInt(dict.value)"
+            :label="dict.label"
+            :value="parseInt(dict.value)"
+          />
         </el-select>
       </el-form-item>
       <el-form-item>
-        <el-button type="primary" @click="getList">Query</el-button>
+        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
+        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
+        <el-button
+          type="primary"
+          @click="openModal('create')"
+          v-hasPermi="['system:notice:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
       </el-form-item>
     </el-form>
-    <div style="width: 100%; height: 600px">
-      <el-auto-resizer>
-        <template #default="{ height, width }">
-          <el-table-v2
-            :columns="columns"
-            :data="tableData"
-            :width="width"
-            :height="height - 50"
-            fixed
-          />
+
+    <!-- 列表 -->
+    <el-table v-loading="loading" :data="list" align="center">
+      <el-table-column label="公告编号" align="center" prop="id" />
+      <el-table-column label="公告标题" align="center" prop="title" />
+      <el-table-column label="公告类型" align="center" prop="type">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.SYSTEM_NOTICE_TYPE" :value="scope.row.type" />
         </template>
-      </el-auto-resizer>
-    </div>
-    <div class="mt-2">
-      <el-pagination
-        :current-page="queryParms.pageNo"
-        :page-size="queryParms.pageSize"
-        :page-sizes="[10, 20, 30, 50, 100]"
-        layout="total, sizes, prev, pager, next, jumper"
-        :total="tableTotal"
-        @size-change="getList"
-        @current-change="getList"
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="创建时间"
+        align="center"
+        prop="createTime"
+        width="180"
+        :formatter="dateFormatter"
       />
-    </div>
-  </ContentWrap>
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button
+            link
+            type="primary"
+            @click="openModal('update', scope.row.id)"
+            v-hasPermi="['system:notice:update']"
+          >
+            编辑
+          </el-button>
+          <el-button
+            link
+            type="danger"
+            @click="handleDelete(scope.row.id)"
+            v-hasPermi="['system:notice:delete']"
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <!-- 分页 -->
+    <Pagination
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </content-wrap>
+
+  <!-- 表单弹窗:添加/修改 -->
+  <notice-form ref="modalRef" @success="getList" />
 </template>
 <script setup lang="tsx">
-import dayjs from 'dayjs'
-import { Column, ElPagination, ElTableV2, TableV2FixedDir } from 'element-plus'
+import { DICT_TYPE, getDictOptions } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
 import * as NoticeApi from '@/api/system/notice'
-import { XTextButton } from '@/components/XButton'
 import { DictTag } from '@/components/DictTag'
+import NoticeForm from './form.vue'
+const message = useMessage() // 消息弹窗
 const { t } = useI18n() // 国际化
 
-const columns: Column<any>[] = [
-  {
-    key: 'id',
-    dataKey: 'id', //需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填id
-    title: 'id', //显示在单元格表头的文本
-    width: 80, //当前列的宽度,必须设置
-    fixed: true //是否固定列
-  },
-  {
-    key: 'title',
-    dataKey: 'title',
-    title: '公告标题',
-    width: 180
-  },
-  {
-    key: 'type',
-    dataKey: 'type',
-    title: '公告类型',
-    width: 180,
-    cellRenderer: ({ cellData: type }) => (
-      <DictTag type={DICT_TYPE.SYSTEM_NOTICE_TYPE} value={type}></DictTag>
-    )
-  },
-  {
-    key: 'status',
-    dataKey: 'status',
-    title: t('common.status'),
-    width: 180,
-    cellRenderer: ({ cellData: status }) => (
-      <DictTag type={DICT_TYPE.COMMON_STATUS} value={status}></DictTag>
-    )
-  },
-  {
-    key: 'content',
-    dataKey: 'content',
-    title: '公告内容',
-    width: 400,
-    cellRenderer: ({ cellData: content }) => <span v-html={content}></span>
-  },
-  {
-    key: 'createTime',
-    dataKey: 'createTime',
-    title: t('common.createTime'),
-    width: 180,
-    cellRenderer: ({ cellData: createTime }) => (
-      <>{dayjs(createTime).format('YYYY-MM-DD HH:mm:ss')}</>
-    )
-  },
-  {
-    key: 'actionbtns',
-    dataKey: 'actionbtns', //需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填id
-    title: '操作', //显示在单元格表头的文本
-    width: 160, //当前列的宽度,必须设置
-    fixed: TableV2FixedDir.RIGHT, //是否固定列
-    align: 'center',
-    cellRenderer: ({ cellData: id }) => (
-      <>
-        <XTextButton
-          preIcon="ep:delete"
-          title={t('action.edit')}
-          onClick={handleUpdate.bind(this, id)}
-        ></XTextButton>
-        <XTextButton
-          preIcon="ep:delete"
-          title={t('action.del')}
-          onClick={handleDelete.bind(this, id)}
-        ></XTextButton>
-      </>
-    )
-  }
-]
-
-const tableData = ref([])
-
-const tableTotal = ref(0)
-
-const queryParms = reactive({
+const loading = ref(true) // 列表的加载中
+const total = ref(0) // 列表的总页数
+const list = ref([]) // 列表的数据
+const queryParams = reactive({
   title: '',
+  type: undefined,
   status: undefined,
   pageNo: 1,
   pageSize: 100
 })
+const queryFormRef = ref() // 搜索的表单
 
+/** 查询公告列表 */
 const getList = async () => {
-  const res = await NoticeApi.getNoticePageApi(queryParms)
-  tableData.value = res.list
-  tableTotal.value = res.total
+  loading.value = true
+  try {
+    const data = await NoticeApi.getNoticePage(queryParams)
+
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
 }
 
-const handleUpdate = (id) => {
-  console.info(id)
+/** 添加/修改操作 */
+const modalRef = ref()
+const openModal = (type: string, id?: number) => {
+  modalRef.value.openModal(type, id)
 }
 
-const handleDelete = (id) => {
-  console.info(id)
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await NoticeApi.deleteNotice(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
 }
 
-getList()
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
 </script>

+ 0 - 148
src/views/system/notice/indexd.vue

@@ -1,148 +0,0 @@
-<template>
-  <ContentWrap>
-    <!-- 列表 -->
-    <XTable @register="registerTable">
-      <!-- 操作:新增 -->
-      <template #toolbar_buttons>
-        <XButton
-          type="primary"
-          preIcon="ep:zoom-in"
-          :title="t('action.add')"
-          v-hasPermi="['system:notice:create']"
-          @click="handleCreate()"
-        />
-      </template>
-      <template #actionbtns_default="{ row }">
-        <!-- 操作:修改 -->
-        <XTextButton
-          preIcon="ep:edit"
-          :title="t('action.edit')"
-          v-hasPermi="['system:notice:update']"
-          @click="handleUpdate(row.id)"
-        />
-        <!-- 操作:详情 -->
-        <XTextButton
-          preIcon="ep:view"
-          :title="t('action.detail')"
-          v-hasPermi="['system:notice:query']"
-          @click="handleDetail(row.id)"
-        />
-        <!-- 操作:删除 -->
-        <XTextButton
-          preIcon="ep:delete"
-          :title="t('action.del')"
-          v-hasPermi="['system:notice:delete']"
-          @click="deleteData(row.id)"
-        />
-      </template>
-    </XTable>
-  </ContentWrap>
-  <!-- 弹窗 -->
-  <XModal id="noticeModel" v-model="dialogVisible" :title="dialogTitle">
-    <!-- 对话框(添加 / 修改) -->
-    <Form
-      ref="formRef"
-      v-if="['create', 'update'].includes(actionType)"
-      :schema="allSchemas.formSchema"
-      :rules="rules"
-    />
-    <!-- 对话框(详情) -->
-    <Descriptions
-      v-if="actionType === 'detail'"
-      :schema="allSchemas.detailSchema"
-      :data="detailData"
-    >
-      <template #content="{ row }">
-        <Editor :model-value="row.content" :readonly="true" />
-      </template>
-    </Descriptions>
-    <template #footer>
-      <!-- 按钮:保存 -->
-      <XButton
-        v-if="['create', 'update'].includes(actionType)"
-        type="primary"
-        :title="t('action.save')"
-        :loading="actionLoading"
-        @click="submitForm()"
-      />
-      <!-- 按钮:关闭 -->
-      <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" />
-    </template>
-  </XModal>
-</template>
-<script setup lang="ts" name="Notice">
-import type { FormExpose } from '@/components/Form'
-// 业务相关的 import
-import * as NoticeApi from '@/api/system/notice'
-import { rules, allSchemas } from './notice.data'
-
-const { t } = useI18n() // 国际化
-const message = useMessage() // 消息弹窗
-// 列表相关的变量
-const [registerTable, { reload, deleteData }] = useXTable({
-  allSchemas: allSchemas,
-  getListApi: NoticeApi.getNoticePageApi,
-  deleteApi: NoticeApi.deleteNoticeApi
-})
-// 弹窗相关的变量
-const dialogVisible = ref(false) // 是否显示弹出层
-const dialogTitle = ref('edit') // 弹出层标题
-const actionType = ref('') // 操作按钮的类型
-const actionLoading = ref(false) // 按钮 Loading
-const formRef = ref<FormExpose>() // 表单 Ref
-const detailData = ref() // 详情 Ref
-
-// 设置标题
-const setDialogTile = (type: string) => {
-  dialogTitle.value = t('action.' + type)
-  actionType.value = type
-  dialogVisible.value = true
-}
-
-// 新增操作
-const handleCreate = () => {
-  setDialogTile('create')
-}
-
-// 修改操作
-const handleUpdate = async (rowId: number) => {
-  setDialogTile('update')
-  // 设置数据
-  const res = await NoticeApi.getNoticeApi(rowId)
-  unref(formRef)?.setValues(res)
-}
-
-// 详情操作
-const handleDetail = async (rowId: number) => {
-  setDialogTile('detail')
-  // 设置数据
-  const res = await NoticeApi.getNoticeApi(rowId)
-  detailData.value = res
-}
-
-// 提交新增/修改的表单
-const submitForm = async () => {
-  const elForm = unref(formRef)?.getElFormRef()
-  if (!elForm) return
-  elForm.validate(async (valid) => {
-    if (valid) {
-      actionLoading.value = true
-      // 提交请求
-      try {
-        const data = unref(formRef)?.formModel as NoticeApi.NoticeVO
-        if (actionType.value === 'create') {
-          await NoticeApi.createNoticeApi(data)
-          message.success(t('common.createSuccess'))
-        } else {
-          await NoticeApi.updateNoticeApi(data)
-          message.success(t('common.updateSuccess'))
-        }
-        dialogVisible.value = false
-      } finally {
-        actionLoading.value = false
-        await reload()
-      }
-    }
-  })
-}
-</script>

+ 0 - 103
src/views/system/notice/indexh.vue

@@ -1,103 +0,0 @@
-<template>
-  <ContentWrap>
-    <div style="width: 100%; height: 500px">
-      <el-auto-resizer>
-        <template #default="{ height, width }">
-          <el-table-v2 :columns="columns" :data="tableData" :width="width" :height="height" fixed />
-        </template>
-      </el-auto-resizer>
-      <el-pagination
-        :current-page="queryParms.pageNo"
-        :page-size="queryParms.pageSize"
-        layout="total, prev, pager, next"
-        :total="tableTotal"
-        @size-change="getList"
-        @current-change="getList"
-      />
-    </div>
-  </ContentWrap>
-</template>
-<script setup lang="ts">
-import { Column, TableV2FixedDir } from 'element-plus'
-import * as NoticeApi from '@/api/system/notice'
-import { XTextButton } from '@/components/XButton'
-const { t } = useI18n() // 国际化
-
-const columns: Column<any>[] = [
-  {
-    key: 'id',
-    dataKey: 'id', //需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填id
-    title: 'id', //显示在单元格表头的文本
-    width: 80, //当前列的宽度,必须设置
-    fixed: true //是否固定列
-  },
-  {
-    key: 'title',
-    dataKey: 'title',
-    title: '公告标题',
-    width: 180
-  },
-  {
-    key: 'type',
-    dataKey: 'type',
-    title: '公告类型',
-    width: 180
-  },
-  {
-    key: 'status',
-    dataKey: 'status',
-    title: t('common.status'),
-    width: 180
-  },
-  {
-    key: 'content',
-    dataKey: 'content',
-    title: '公告内容',
-    width: 180
-  },
-  {
-    key: 'createTime',
-    dataKey: 'createTime',
-    title: t('common.createTime'),
-    width: 180
-  },
-  {
-    key: 'actionbtns',
-    dataKey: 'actionbtns', //需要渲染当前列的数据字段,如{id:9527,name:'Mike'},则填id
-    title: '操作', //显示在单元格表头的文本
-    width: 80, //当前列的宽度,必须设置
-    fixed: TableV2FixedDir.RIGHT, //是否固定列
-    align: 'center',
-    cellRenderer: (date) =>
-      h(XTextButton, {
-        onClick: () => handleDelete(date.rowData),
-        type: 'danger',
-        preIcon: 'ep:delete',
-        title: t('action.del')
-      })
-  }
-]
-
-const tableData = ref([])
-
-const tableTotal = ref(0)
-
-const queryParms = reactive({
-  title: '',
-  status: undefined,
-  pageNo: 1,
-  pageSize: 10
-})
-
-const getList = async () => {
-  const res = await NoticeApi.getNoticePageApi(queryParms)
-  tableData.value = res.list
-  tableTotal.value = res.total
-}
-
-const handleDelete = (row) => {
-  console.info(row.id)
-}
-
-getList()
-</script>

+ 0 - 59
src/views/system/notice/notice.data.ts

@@ -1,59 +0,0 @@
-import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
-const { t } = useI18n() // 国际化
-
-// 表单校验
-export const rules = reactive({
-  title: [required],
-  type: [required]
-})
-
-// CrudSchema
-const crudSchemas = reactive<VxeCrudSchema>({
-  primaryKey: 'id',
-  primaryType: 'seq',
-  action: true,
-  columns: [
-    {
-      title: '公告标题',
-      field: 'title',
-      isSearch: true
-    },
-    {
-      title: '公告类型',
-      field: 'type',
-      dictType: DICT_TYPE.SYSTEM_NOTICE_TYPE,
-      dictClass: 'number'
-    },
-    {
-      title: t('common.status'),
-      field: 'status',
-      dictType: DICT_TYPE.COMMON_STATUS,
-      dictClass: 'number',
-      isSearch: true
-    },
-    {
-      title: '公告内容',
-      field: 'content',
-      table: {
-        type: 'html'
-      },
-      form: {
-        component: 'Editor',
-        colProps: {
-          span: 24
-        },
-        componentProps: {
-          valueHtml: ''
-        }
-      },
-      isTable: false
-    },
-    {
-      title: t('common.createTime'),
-      field: 'createTime',
-      formatter: 'formatDate',
-      isForm: false
-    }
-  ]
-})
-export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

+ 4 - 0
src/views/system/oauth2/client/client.data.ts

@@ -22,6 +22,10 @@ const crudSchemas = reactive<VxeCrudSchema>({
   primaryType: null,
   action: true,
   columns: [
+    {
+      title: '客户端端号',
+      field: 'clientId'
+    },
     {
       title: '客户端密钥',
       field: 'secret'

+ 2 - 1
src/views/system/sms/smsLog/index.vue

@@ -44,12 +44,13 @@ const [registerTable, { exportList }] = useXTable({
 
 // 弹窗相关的变量
 const dialogVisible = ref(false) // 是否显示弹出层
-const dialogTitle = ref('edit') // 弹出层标题
+const dialogTitle = ref(t('action.detail')) // 弹出层标题
 const actionType = ref('') // 操作按钮的类型
 // ========== 详情相关 ==========
 const detailData = ref() // 详情 Ref
 const handleDetail = (row: SmsLoglApi.SmsLogVO) => {
   // 设置数据
+  actionType.value = 'detail'
   detailData.value = row
   dialogVisible.value = true
 }

+ 14 - 3
src/views/system/sms/smsLog/sms.log.data.ts

@@ -1,6 +1,9 @@
 import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
+import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
+
 const { t } = useI18n() // 国际化
 
+const authorizedGrantOptions = getStrDictOptions(DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE)
 // CrudSchema
 const crudSchemas = reactive<VxeCrudSchema>({
   primaryKey: 'id',
@@ -25,9 +28,17 @@ const crudSchemas = reactive<VxeCrudSchema>({
     {
       title: '短信渠道',
       field: 'channelId',
-      dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,
-      dictClass: 'number',
-      isSearch: true
+      // dictType: DICT_TYPE.SYSTEM_SMS_CHANNEL_CODE,
+      // dictClass: 'number',
+      isSearch: true,
+      // table: {
+      // component: 'Select',
+      componentProps: {
+        options: authorizedGrantOptions
+        // multiple: false,
+        // filterable: true
+      }
+      // }
     },
     {
       title: '发送状态',

+ 27 - 1
src/views/system/sms/smsTemplate/sms.template.data.ts

@@ -1,6 +1,19 @@
 import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
+import * as smsApi from '@/api/system/sms/smsChannel'
 const { t } = useI18n() // 国际化
-
+const tenantPackageOption = []
+const getTenantPackageOptions = async () => {
+  const res = await smsApi.getSimpleSmsChannels()
+  console.log(res, 'resresres')
+  res.forEach((tenantPackage: TenantPackageVO) => {
+    tenantPackageOption.push({
+      key: tenantPackage.id,
+      value: tenantPackage.id,
+      label: tenantPackage.signature
+    })
+  })
+}
+getTenantPackageOptions()
 // 表单校验
 export const rules = reactive({
   type: [required],
@@ -20,6 +33,19 @@ const crudSchemas = reactive<VxeCrudSchema>({
   action: true,
   actionWidth: '280',
   columns: [
+    {
+      title: '短信渠道编码',
+      field: 'channelId',
+      isSearch: false,
+      isForm: true,
+      isTable: false,
+      form: {
+        component: 'Select',
+        componentProps: {
+          options: tenantPackageOption
+        }
+      }
+    },
     {
       title: '模板编码',
       field: 'code',

+ 24 - 1
src/views/system/tenant/index.vue

@@ -123,14 +123,37 @@ const setDialogTile = (type: string) => {
 }
 
 // 新增操作
-const handleCreate = () => {
+const handleCreate = async () => {
   // 重置表单
   setDialogTile('create')
+  await nextTick()
+  console.log(allSchemas.formSchema, 'allSchemas.formSchema')
+  if (allSchemas.formSchema[4].field !== 'username') {
+    unref(formRef)?.addSchema(
+      {
+        field: 'username',
+        label: '用户名称',
+        component: 'Input'
+      },
+      0
+    )
+    unref(formRef)?.addSchema(
+      {
+        field: 'password',
+        label: '用户密码',
+        component: 'InputPassword'
+      },
+      1
+    )
+  }
 }
 
 // 修改操作
 const handleUpdate = async (rowId: number) => {
   setDialogTile('update')
+  await nextTick()
+  unref(formRef)?.delSchema('username')
+  unref(formRef)?.delSchema('password')
   // 设置数据
   const res = await TenantApi.getTenantApi(rowId)
   unref(formRef)?.setValues(res)

+ 35 - 2
src/views/system/tenant/tenant.data.ts

@@ -19,12 +19,44 @@ const getTenantPackageOptions = async () => {
 }
 getTenantPackageOptions()
 
+const validateName = (rule: any, value: any, callback: any) => {
+  const reg = /^[a-zA-Z0-9]{4,30}$/
+  if (value === '') {
+    callback(new Error('请输入用户名称'))
+  } else {
+    console.log(reg.test(rule), 'reg.test(rule)')
+    if (!reg.test(value)) {
+      callback(new Error('用户名称由 数字、字母 组成'))
+    } else {
+      callback()
+    }
+  }
+}
+const validateMobile = (rule: any, value: any, callback: any) => {
+  const reg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
+  if (value === '') {
+    callback(new Error('请输入联系手机'))
+  } else {
+    if (!reg.test(value)) {
+      callback(new Error('请输入正确的手机号'))
+    } else {
+      callback()
+    }
+  }
+}
+
 // 表单校验
 export const rules = reactive({
   name: [required],
   packageId: [required],
   contactName: [required],
-  contactMobile: [required],
+  contactMobile: [
+    required,
+    {
+      validator: validateMobile,
+      trigger: 'blur'
+    }
+  ],
   accountCount: [required],
   expireTime: [required],
   username: [
@@ -34,7 +66,8 @@ export const rules = reactive({
       max: 30,
       trigger: 'blur',
       message: '用户名称长度为 4-30 个字符'
-    }
+    },
+    { validator: validateName, trigger: 'blur' }
   ],
   password: [
     required,

+ 48 - 48
src/views/system/tenantPackage/index.vue

@@ -15,54 +15,54 @@
         <XTextButton preIcon="ep:delete" :title="t('action.del')" @click="deleteData(row.id)" />
       </template>
     </XTable>
-  </ContentWrap>
-  <XModal v-model="dialogVisible" :title="dialogTitle">
-    <!-- 对话框(添加 / 修改) -->
-    <Form
-      v-if="['create', 'update'].includes(actionType)"
-      :schema="allSchemas.formSchema"
-      :rules="rules"
-      ref="formRef"
-    >
-      <template #menuIds>
-        <el-card>
-          <template #header>
-            <div class="card-header">
-              全选/全不选:
-              <el-switch
-                v-model="treeNodeAll"
-                inline-prompt
-                active-text="是"
-                inactive-text="否"
-                @change="handleCheckedTreeNodeAll()"
-              />
-            </div>
-          </template>
-          <el-tree
-            ref="treeRef"
-            node-key="id"
-            show-checkbox
-            :props="defaultProps"
-            :data="menuOptions"
-            empty-text="加载中,请稍后"
-          />
-        </el-card>
-      </template>
-    </Form>
-    <!-- 操作按钮 -->
-    <template #footer>
-      <!-- 按钮:保存 -->
-      <XButton
+    <XModal v-model="dialogVisible" :title="dialogTitle">
+      <!-- 对话框(添加 / 修改) -->
+      <Form
         v-if="['create', 'update'].includes(actionType)"
-        type="primary"
-        :title="t('action.save')"
-        :loading="loading"
-        @click="submitForm()"
-      />
-      <!-- 按钮:关闭 -->
-      <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" />
-    </template>
-  </XModal>
+        :schema="allSchemas.formSchema"
+        :rules="rules"
+        ref="formRef"
+      >
+        <template #menuIds>
+          <el-card class="cardHeight">
+            <template #header>
+              <div class="card-header">
+                全选/全不选:
+                <el-switch
+                  v-model="treeNodeAll"
+                  inline-prompt
+                  active-text="是"
+                  inactive-text="否"
+                  @change="handleCheckedTreeNodeAll()"
+                />
+              </div>
+            </template>
+            <el-tree
+              ref="treeRef"
+              node-key="id"
+              show-checkbox
+              :props="defaultProps"
+              :data="menuOptions"
+              empty-text="加载中,请稍候"
+            />
+          </el-card>
+        </template>
+      </Form>
+      <!-- 操作按钮 -->
+      <template #footer>
+        <!-- 按钮:保存 -->
+        <XButton
+          v-if="['create', 'update'].includes(actionType)"
+          type="primary"
+          :title="t('action.save')"
+          :loading="loading"
+          @click="submitForm()"
+        />
+        <!-- 按钮:关闭 -->
+        <XButton :loading="loading" :title="t('dialog.close')" @click="dialogVisible = false" />
+      </template>
+    </XModal>
+  </ContentWrap>
 </template>
 <script setup lang="ts" name="TenantPackage">
 import { handleTree, defaultProps } from '@/utils/tree'
@@ -179,7 +179,7 @@ onMounted(async () => {
 // getList()
 </script>
 <style scoped>
-.el-card {
+.cardHeight {
   width: 100%;
   max-height: 400px;
   overflow-y: scroll;

+ 22 - 2
src/views/system/user/user.data.ts

@@ -1,6 +1,18 @@
 import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
 // 国际化
 const { t } = useI18n()
+const validateMobile = (rule: any, value: any, callback: any) => {
+  const reg = /^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\d{8}$/
+  if (value === '') {
+    callback(new Error('请输入联系手机'))
+  } else {
+    if (!reg.test(value)) {
+      callback(new Error('请输入正确的手机号'))
+    } else {
+      callback()
+    }
+  }
+}
 // 表单校验
 export const rules = reactive({
   username: [required],
@@ -17,12 +29,13 @@ export const rules = reactive({
   ],
   status: [required],
   mobile: [
+    required,
     {
-      required: true,
       len: 11,
       trigger: 'blur',
       message: '请输入正确的手机号码'
-    }
+    },
+    { validator: validateMobile, trigger: 'blur' }
   ]
 })
 // crudSchemas
@@ -47,6 +60,13 @@ const crudSchemas = reactive<VxeCrudSchema>({
         component: 'InputPassword'
       }
     },
+    {
+      title: '用户' + t('profile.user.sex'),
+      field: 'sex',
+      dictType: DICT_TYPE.SYSTEM_USER_SEX,
+      dictClass: 'number',
+      table: { show: false }
+    },
     {
       title: '用户昵称',
       field: 'nickname'