Przeglądaj źródła

!71 测试所提bug修改
Merge pull request !71 from 周建/master

芋道源码 2 lat temu
rodzic
commit
c65a9d92bb

+ 1 - 1
src/api/infra/fileConfig/index.ts

@@ -16,7 +16,7 @@ export interface FileClientConfig {
 export interface FileConfigVO {
   id: number
   name: string
-  storage: number
+  storage: any
   master: boolean
   visible: boolean
   config: FileClientConfig

+ 50 - 0
src/config/axios/request.ts

@@ -0,0 +1,50 @@
+import { service } from './service'
+
+import { config } from './config'
+
+const { default_headers } = config
+
+const request = (option: any) => {
+  const { url, method, params, data, headersType, responseType } = option
+  return service({
+    url: url,
+    method,
+    params,
+    data,
+    responseType: responseType,
+    headers: {
+      'Content-Type': headersType || default_headers
+    }
+  })
+}
+export default {
+  get: async <T = any>(option: any) => {
+    const res = await request({ method: 'GET', ...option })
+    return res as unknown as T
+  },
+  post: async <T = any>(option: any) => {
+    const res = await request({ method: 'POST', ...option })
+    return res as unknown as T
+  },
+  delete: async <T = any>(option: any) => {
+    const res = await request({ method: 'DELETE', ...option })
+    return res as unknown as T
+  },
+  put: async <T = any>(option: any) => {
+    const res = await request({ method: 'PUT', ...option })
+    return res as unknown as T
+  },
+  patch: async <T = any>(option: any) => {
+    const res = await request({ method: 'PATCH', ...option })
+    return res as unknown as T
+  },
+  download: async <T = any>(option: any) => {
+    const res = await request({ method: 'GET', responseType: 'blob', ...option })
+    return res as unknown as Promise<T>
+  },
+  upload: async <T = any>(option: any) => {
+    option.headersType = 'multipart/form-data'
+    const res = await request({ method: 'POST', ...option })
+    return res as unknown as Promise<T>
+  }
+}

+ 5 - 3
src/views/bpm/form/formEditor.vue

@@ -12,9 +12,11 @@
       <div ref="editor" v-if="dialogVisible1">
         <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>
     </Dialog>

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

@@ -146,8 +146,8 @@
             style="width: 100%"
           >
             <el-option
-              v-for="dict in getDictOptions(DICT_TYPE.BPM_MODEL_CATEGORY)"
-              :key="dict.value"
+              v-for="(dict, index) in getDictOptions(DICT_TYPE.BPM_MODEL_CATEGORY)"
+              :key="index"
               :label="dict.label"
               :value="dict.value"
             />
@@ -434,9 +434,9 @@ const handleUpdate = async (rowId: number) => {
   // 设置数据
   saveForm.value = await ModelApi.getModelApi(rowId)
   if (saveForm.value.category == null) {
-    saveForm.value.category = 1
+    saveForm.value.category = '1'
   } else {
-    saveForm.value.category = Number(saveForm.value.category)
+    saveForm.value.category = saveForm.value.category
   }
 }
 

+ 90 - 0
src/views/infra/config/config.data.ts

@@ -0,0 +1,90 @@
+import type { VxeCrudSchema } from '@/hooks/web/useVxeCrudSchemas'
+const { t } = useI18n() // 国际化
+
+// 表单校验
+export const rules = reactive({
+  category: [required],
+  name: [required],
+  key: [required],
+  value: [required]
+})
+
+// CrudSchema
+const crudSchemas = reactive<VxeCrudSchema>({
+  primaryKey: 'id',
+  primaryType: null,
+  action: true,
+  columns: [
+    {
+      title: '参数分类',
+      field: 'category'
+    },
+    {
+      title: '参数名称',
+      field: 'name',
+      isSearch: true
+    },
+    {
+      title: '参数键名',
+      field: 'key',
+      isSearch: true
+    },
+    {
+      title: '参数键值',
+      field: 'value'
+    },
+    {
+      title: '系统内置',
+      field: 'type',
+      dictType: DICT_TYPE.INFRA_CONFIG_TYPE,
+      dictClass: 'number',
+      isSearch: true
+    },
+    {
+      title: '是否可见',
+      field: 'visible',
+      table: {
+        slots: {
+          default: 'visible_default'
+        }
+      },
+      form: {
+        component: 'RadioButton',
+        componentProps: {
+          options: [
+            { label: '是', value: true },
+            { label: '否', value: false }
+          ]
+        }
+      }
+    },
+    {
+      title: t('form.remark'),
+      field: 'remark',
+      isTable: false,
+      form: {
+        component: 'Input',
+        componentProps: {
+          type: 'textarea',
+          rows: 4
+        },
+        colProps: {
+          span: 24
+        }
+      }
+    },
+    {
+      title: t('common.createTime'),
+      field: 'createTime',
+      formatter: 'formatDate',
+      isForm: false,
+      search: {
+        show: true,
+        itemRender: {
+          name: 'XDataTimePicker'
+        }
+      }
+    }
+  ]
+})
+export const { allSchemas } = useVxeCrudSchemas(crudSchemas)

+ 0 - 131
src/views/infra/config/form.vue

@@ -1,131 +0,0 @@
-<template>
-  <Dialog :title="modelTitle" v-model="modelVisible">
-    <el-form
-      ref="formRef"
-      :model="formData"
-      :rules="formRules"
-      label-width="80px"
-      v-loading="formLoading"
-    >
-      <el-form-item label="参数分类" prop="category">
-        <el-input v-model="formData.category" placeholder="请输入参数分类" />
-      </el-form-item>
-      <el-form-item label="参数名称" prop="name">
-        <el-input v-model="formData.name" placeholder="请输入参数名称" />
-      </el-form-item>
-      <el-form-item label="参数键名" prop="key">
-        <el-input v-model="formData.key" placeholder="请输入参数键名" />
-      </el-form-item>
-      <el-form-item label="参数键值" prop="value">
-        <el-input v-model="formData.value" placeholder="请输入参数键值" />
-      </el-form-item>
-      <el-form-item label="是否可见" prop="visible">
-        <el-radio-group v-model="formData.visible">
-          <el-radio
-            v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
-            :key="dict.value"
-            :label="dict.value"
-          >
-            {{ dict.label }}
-          </el-radio>
-        </el-radio-group>
-      </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, getBoolDictOptions } from '@/utils/dict'
-import * as ConfigApi from '@/api/infra/config'
-
-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,
-  category: '',
-  name: '',
-  key: '',
-  value: '',
-  visible: true,
-  remark: ''
-})
-const formRules = reactive({
-  category: [{ required: true, message: '参数分类不能为空', trigger: 'blur' }],
-  name: [{ required: true, message: '参数名称不能为空', trigger: 'blur' }],
-  key: [{ required: true, message: '参数键名不能为空', trigger: 'blur' }],
-  value: [{ required: true, message: '参数键值不能为空', trigger: 'blur' }],
-  visible: [{ 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 ConfigApi.getConfig(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 ConfigApi.ConfigVO
-    if (formType.value === 'create') {
-      await ConfigApi.createConfig(data)
-      message.success(t('common.createSuccess'))
-    } else {
-      await ConfigApi.updateConfig(data)
-      message.success(t('common.updateSuccess'))
-    }
-    modelVisible.value = false
-    // 发送操作成功的事件
-    emit('success')
-  } finally {
-    formLoading.value = false
-  }
-}
-
-/** 重置表单 */
-const resetForm = () => {
-  formData.value = {
-    id: undefined,
-    category: '',
-    name: '',
-    key: '',
-    value: '',
-    visible: true,
-    remark: ''
-  }
-  formRef.value?.resetFields()
-}
-</script>

+ 162 - 180
src/views/infra/config/index.vue

@@ -1,203 +1,185 @@
 <template>
-  <content-wrap>
-    <!-- 搜索工作栏 -->
-    <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
-      <el-form-item label="参数名称" prop="name">
-        <el-input
-          v-model="queryParams.name"
-          placeholder="请输入参数名称"
-          clearable
-          @keyup.enter="handleQuery"
+  <ContentWrap>
+    <!-- 列表 -->
+    <XTable @register="registerTable">
+      <template #toolbar_buttons>
+        <!-- 操作:新增 -->
+        <XButton
+          type="primary"
+          preIcon="ep:zoom-in"
+          :title="t('action.add')"
+          v-hasPermi="['infra:config:create']"
+          @click="handleCreate()"
         />
-      </el-form-item>
-      <el-form-item label="参数键名" prop="key">
-        <el-input
-          v-model="queryParams.key"
-          placeholder="请输入参数键名"
-          clearable
-          @keyup.enter="handleQuery"
+        <!-- 操作:导出 -->
+        <XButton
+          type="warning"
+          preIcon="ep:download"
+          :title="t('action.export')"
+          v-hasPermi="['infra:config:export']"
+          @click="exportList('配置.xls')"
         />
-      </el-form-item>
-      <el-form-item label="系统内置" prop="type">
-        <el-select v-model="queryParams.type" placeholder="请选择系统内置" clearable>
-          <el-option
-            v-for="dict in getDictOptions(DICT_TYPE.INFRA_CONFIG_TYPE)"
-            :key="parseInt(dict.value)"
-            :label="dict.label"
-            :value="parseInt(dict.value)"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="创建时间" prop="createTime">
-        <el-date-picker
-          v-model="queryParams.createTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="daterange"
-          range-separator="-"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+      </template>
+      <template #visible_default="{ row }">
+        <span>{{ row.visible ? '是' : '否' }} </span>
+      </template>
+      <template #actionbtns_default="{ row }">
+        <!-- 操作:修改 -->
+        <XTextButton
+          preIcon="ep:edit"
+          :title="t('action.edit')"
+          v-hasPermi="['infra:config:update']"
+          @click="handleUpdate(row.id)"
         />
-      </el-form-item>
-      <el-form-item>
-        <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="['infra:config:create']">
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
-        </el-button>
-        <el-button
-          type="success"
-          plain
-          @click="handleExport"
-          :loading="exportLoading"
-          v-hasPermi="['infra:config:export']"
-        >
-          <Icon icon="ep:download" class="mr-5px" /> 导出
-        </el-button>
-      </el-form-item>
-    </el-form>
+        <!-- 操作:详情 -->
+        <XTextButton
+          preIcon="ep:view"
+          :title="t('action.detail')"
+          v-hasPermi="['infra:config:query']"
+          @click="handleDetail(row.id)"
+        />
+        <!-- 操作:删除 -->
+        <XTextButton
+          preIcon="ep:delete"
+          :title="t('action.del')"
+          v-hasPermi="['infra:config:delete']"
+          @click="deleteData(row.id)"
+        />
+      </template>
+    </XTable>
+  </ContentWrap>
 
-    <!-- 列表 -->
-    <el-table v-loading="loading" :data="list" align="center">
-      <el-table-column label="参数主键" align="center" prop="id" />
-      <el-table-column label="参数分类" align="center" prop="category" />
-      <el-table-column label="参数名称" align="center" prop="name" :show-overflow-tooltip="true" />
-      <el-table-column label="参数键名" align="center" prop="key" :show-overflow-tooltip="true" />
-      <el-table-column label="参数键值" align="center" prop="value" />
-      <el-table-column label="是否可见" align="center" prop="visible">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.visible" />
-        </template>
-      </el-table-column>
-      <el-table-column label="系统内置" align="center" prop="type">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.INFRA_CONFIG_TYPE" :value="scope.row.type" />
-        </template>
-      </el-table-column>
-      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
-      <el-table-column
-        label="创建时间"
-        align="center"
-        prop="createTime"
-        width="180"
-        :formatter="dateFormatter"
-      />
-      <el-table-column label="操作" align="center">
-        <template #default="scope">
-          <el-button
-            link
-            type="primary"
-            @click="openModal('update', scope.row.id)"
-            v-hasPermi="['infra:config:update']"
-          >
-            编辑
-          </el-button>
-          <el-button
-            link
-            type="danger"
-            @click="handleDelete(scope.row.id)"
-            v-hasPermi="['infra:config:delete']"
-          >
-            删除
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <!-- 分页 -->
-    <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
-      v-model:limit="queryParams.pageSize"
-      @pagination="getList"
+  <XModal v-model="dialogVisible" :title="dialogTitle">
+    <!-- 对话框(添加 / 修改) -->
+    <Form
+      v-if="['create', 'update'].includes(actionType)"
+      :schema="allSchemas.formSchema"
+      :rules="rules"
+      ref="formRef"
     />
-  </content-wrap>
-
-  <!-- 表单弹窗:添加/修改 -->
-  <config-form ref="modalRef" @success="getList" />
+    <!-- 对话框(详情) -->
+    <Descriptions
+      v-if="actionType === 'detail'"
+      :schema="allSchemas.detailSchema"
+      :data="detailData"
+    >
+      <template #visible="{ row }">
+        <span>{{ row.visible ? '是' : '否' }} </span>
+      </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="Config">
-import { DICT_TYPE, getDictOptions } from '@/utils/dict'
-import { dateFormatter } from '@/utils/formatTime'
-import download from '@/utils/download'
+import type { FormExpose } from '@/components/Form'
+// 业务相关的 import
 import * as ConfigApi from '@/api/infra/config'
-import ConfigForm from './form.vue'
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
+import { rules, allSchemas } from './config.data'
 
-const loading = ref(true) // 列表的加载中
-const total = ref(0) // 列表的总页数
-const list = ref([]) // 列表的数据
-const queryParams = reactive({
-  pageNo: 1,
-  pageSize: 10,
-  name: undefined,
-  key: undefined,
-  type: undefined,
-  createTime: []
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+// 列表相关的变量
+const [registerTable, { reload, deleteData, exportList }] = useXTable({
+  allSchemas: allSchemas,
+  getListApi: ConfigApi.getConfigPageApi,
+  deleteApi: ConfigApi.deleteConfigApi,
+  exportListApi: ConfigApi.exportConfigApi
 })
-const queryFormRef = ref() // 搜索的表单
-const exportLoading = ref(false) // 导出的加载中
 
-/** 查询参数列表 */
-const getList = async () => {
-  loading.value = true
-  try {
-    const data = await ConfigApi.getConfigPage(queryParams)
-    list.value = data.list
-    total.value = data.total
-  } finally {
-    loading.value = false
-  }
-}
+// ========== CRUD 相关 ==========
+const actionLoading = ref(false) // 遮罩层
+const actionType = ref('') // 操作按钮的类型
+const dialogVisible = ref(false) // 是否显示弹出层
+const dialogTitle = ref('edit') // 弹出层标题
+const formRef = ref<FormExpose>() // 表单 Ref
+const detailData = ref() // 详情 Ref
 
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  queryParams.pageNo = 1
-  getList()
+// 设置标题
+const setDialogTile = (type: string) => {
+  dialogTitle.value = t('action.' + type)
+  actionType.value = type
+  dialogVisible.value = true
 }
 
-/** 重置按钮操作 */
-const resetQuery = () => {
-  queryFormRef.value.resetFields()
-  handleQuery()
+// 新增操作
+const handleCreate = async () => {
+  setDialogTile('create')
+  await nextTick()
+  console.log(allSchemas.formSchema, 'allSchemas.formSchema')
+  if (allSchemas.formSchema[2].field !== 'key') {
+    unref(formRef)?.addSchema(
+      {
+        field: 'key',
+        label: '参数键名',
+        component: 'Input'
+      },
+      2
+    )
+    unref(formRef)?.addSchema(
+      {
+        field: 'value',
+        label: '参数键值',
+        component: 'Input'
+      },
+      3
+    )
+  }
 }
 
-/** 添加/修改操作 */
-const modalRef = ref()
-const openModal = (type: string, id?: number) => {
-  modalRef.value.openModal(type, id)
-}
+// 修改操作
+const handleUpdate = async (rowId: number) => {
+  setDialogTile('update')
+  // 设置数据
+  const res = await ConfigApi.getConfigApi(rowId)
+  unref(formRef)?.delSchema('key')
+  unref(formRef)?.delSchema('value')
 
-/** 删除按钮操作 */
-const handleDelete = async (id: number) => {
-  try {
-    // 删除的二次确认
-    await message.delConfirm()
-    // 发起删除
-    await ConfigApi.deleteConfig(id)
-    message.success(t('common.delSuccess'))
-    // 刷新列表
-    await getList()
-  } catch {}
+  unref(formRef)?.setValues(res)
 }
 
-/** 导出按钮操作 */
-const handleExport = async () => {
-  try {
-    // 导出的二次确认
-    await message.exportConfirm()
-    // 发起导出
-    exportLoading.value = true
-    const data = await ConfigApi.exportConfigApi(queryParams)
-    download.excel(data, '参数配置.xls')
-  } catch {
-  } finally {
-    exportLoading.value = false
-  }
+// 详情操作
+const handleDetail = async (rowId: number) => {
+  setDialogTile('detail')
+  const res = await ConfigApi.getConfigApi(rowId)
+  detailData.value = res
 }
 
-/** 初始化 **/
-onMounted(() => {
-  getList()
-})
+// 提交按钮
+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 ConfigApi.ConfigVO
+        if (actionType.value === 'create') {
+          await ConfigApi.createConfigApi(data)
+          message.success(t('common.createSuccess'))
+        } else {
+          await ConfigApi.updateConfigApi(data)
+          message.success(t('common.updateSuccess'))
+        }
+        dialogVisible.value = false
+      } finally {
+        actionLoading.value = false
+        // 刷新列表
+        await reload()
+      }
+    }
+  })
+}
 </script>

+ 2 - 2
src/views/infra/fileConfig/index.vue

@@ -183,7 +183,7 @@ const detailData = ref() // 详情 Ref
 const form = ref<FileConfigApi.FileConfigVO>({
   id: 0,
   name: '',
-  storage: 0,
+  storage: null,
   master: false,
   visible: false,
   config: {
@@ -216,7 +216,7 @@ const handleCreate = (formEl: FormInstance | undefined) => {
   form.value = {
     id: 0,
     name: '',
-    storage: 0,
+    storage: null,
     master: false,
     visible: false,
     config: {

+ 5 - 1
src/views/infra/fileList/index.vue

@@ -59,6 +59,7 @@
       :on-exceed="handleExceed"
       :on-success="handleFileSuccess"
       :on-error="excelUploadError"
+      :before-remove="beforeRemove"
       :auto-upload="false"
       accept=".jpg, .png, .gif"
     >
@@ -82,7 +83,7 @@
   </XModal>
 </template>
 <script setup lang="ts" name="FileList">
-import type { UploadInstance, UploadRawFile } from 'element-plus'
+import type { UploadInstance, UploadRawFile, UploadProps } from 'element-plus'
 // 业务相关的 import
 import { allSchemas } from './fileList.data'
 import * as FileApi from '@/api/infra/fileList'
@@ -141,6 +142,9 @@ const handleFileSuccess = async (response: any): Promise<void> => {
   uploadDisabled.value = false
   await reload()
 }
+const beforeRemove: UploadProps['beforeRemove'] = () => {
+  uploadDisabled.value = false
+}
 // 文件数超出提示
 const handleExceed = (): void => {
   message.error('最多只能上传一个文件!')

+ 2 - 1
src/views/system/mail/log/log.data.ts

@@ -114,7 +114,8 @@ const crudSchemas = reactive<VxeCrudSchema>({
     {
       title: '创建时间',
       field: 'createTime',
-      isTable: false
+      isTable: false,
+      formatter: 'formatDate'
     }
   ]
 })

+ 5 - 1
src/views/system/tenant/tenant.data.ts

@@ -143,7 +143,11 @@ const crudSchemas = reactive<VxeCrudSchema>({
         }
       },
       form: {
-        component: 'InputNumber'
+        component: 'InputNumber',
+        value: null,
+        componentProps: {
+          min: 1
+        }
       }
     },
     {

+ 1 - 1
src/views/system/tenantPackage/tenantPackage.data.ts

@@ -43,7 +43,7 @@ const crudSchemas = reactive<VxeCrudSchema>({
     {
       title: t('form.remark'),
       field: 'remark',
-      isTable: false,
+      isTable: true,
       isSearch: true,
       form: {
         component: 'Input',

+ 1 - 0
src/views/system/user/index.vue

@@ -394,6 +394,7 @@ const handleUpdate = async (rowId: number) => {
   unref(formRef)?.delSchema('password')
   // 设置数据
   const res = await UserApi.getUserApi(rowId)
+  if (res.sex == 0) res.sex = null
   unref(formRef)?.setValues(res)
 }
 const detailData = ref()

+ 1 - 0
src/views/system/user/user.data.ts

@@ -28,6 +28,7 @@ export const rules = reactive({
     }
   ],
   status: [required],
+  postIds: [{ required: true, message: '请选择岗位', trigger: ['blur', 'change'] }],
   mobile: [
     required,
     {