mirror of
				https://gitee.com/hhyykk/ipms-sjy-ui.git
				synced 2025-11-04 12:18:43 +08:00 
			
		
		
		
	
							
								
								
									
										223
									
								
								src/views/system/user/AddForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								src/views/system/user/AddForm.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,223 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <!-- 添加或修改参数配置对话框 -->
 | 
			
		||||
  <el-dialog
 | 
			
		||||
    :title="title"
 | 
			
		||||
    :modelValue="modelValue"
 | 
			
		||||
    width="600px"
 | 
			
		||||
    append-to-body
 | 
			
		||||
    @close="closeDialog"
 | 
			
		||||
  >
 | 
			
		||||
    <el-form ref="formRef" :model="formData" :rules="rules" label-width="80px">
 | 
			
		||||
      <el-row>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item label="用户昵称" prop="nickname">
 | 
			
		||||
            <el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item label="归属部门" prop="deptId">
 | 
			
		||||
            <el-tree-select
 | 
			
		||||
              node-key="id"
 | 
			
		||||
              v-model="formData.deptId"
 | 
			
		||||
              :data="deptOptions"
 | 
			
		||||
              :props="defaultProps"
 | 
			
		||||
              check-strictly
 | 
			
		||||
              placeholder="请选择归属部门"
 | 
			
		||||
            />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
      <el-row>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item label="手机号码" prop="mobile">
 | 
			
		||||
            <el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item label="邮箱" prop="email">
 | 
			
		||||
            <el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
      <el-row>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item v-if="formData.id === undefined" label="用户名称" prop="username">
 | 
			
		||||
            <el-input v-model="formData.username" placeholder="请输入用户名称" />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item v-if="formData.id === undefined" label="用户密码" prop="password">
 | 
			
		||||
            <el-input
 | 
			
		||||
              v-model="formData.password"
 | 
			
		||||
              placeholder="请输入用户密码"
 | 
			
		||||
              type="password"
 | 
			
		||||
              show-password
 | 
			
		||||
            />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
      <el-row>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item label="用户性别">
 | 
			
		||||
            <el-select v-model="formData.sex" placeholder="请选择">
 | 
			
		||||
              <el-option
 | 
			
		||||
                v-for="dict in sexDictDatas"
 | 
			
		||||
                :key="parseInt(dict.value)"
 | 
			
		||||
                :label="dict.label"
 | 
			
		||||
                :value="parseInt(dict.value)"
 | 
			
		||||
              />
 | 
			
		||||
            </el-select>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
        <el-col :span="12">
 | 
			
		||||
          <el-form-item label="岗位">
 | 
			
		||||
            <el-select v-model="formData.postIds" multiple placeholder="请选择">
 | 
			
		||||
              <el-option
 | 
			
		||||
                v-for="item in postOptions"
 | 
			
		||||
                :key="item.id"
 | 
			
		||||
                :label="item.name"
 | 
			
		||||
                :value="item.id"
 | 
			
		||||
              />
 | 
			
		||||
            </el-select>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
      <el-row>
 | 
			
		||||
        <el-col :span="24">
 | 
			
		||||
          <el-form-item label="备注">
 | 
			
		||||
            <el-input v-model="formData.remark" type="textarea" placeholder="请输入内容" />
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-col>
 | 
			
		||||
      </el-row>
 | 
			
		||||
    </el-form>
 | 
			
		||||
    <template #footer>
 | 
			
		||||
      <div class="dialog-footer">
 | 
			
		||||
        <el-button type="primary" @click="submitForm">确 定</el-button>
 | 
			
		||||
        <el-button @click="cancel">取 消</el-button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
  </el-dialog>
 | 
			
		||||
</template>
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { PostVO } from '@/api/system/post'
 | 
			
		||||
import { createUserApi, updateUserApi } from '@/api/system/user'
 | 
			
		||||
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
 | 
			
		||||
import { defaultProps } from '@/utils/tree'
 | 
			
		||||
import { ElForm, FormItemRule } from 'element-plus'
 | 
			
		||||
import { Arrayable } from 'element-plus/es/utils'
 | 
			
		||||
 | 
			
		||||
type Form = InstanceType<typeof ElForm>
 | 
			
		||||
interface Props {
 | 
			
		||||
  deptOptions?: Tree[]
 | 
			
		||||
  postOptions?: PostVO[] //岗位列表
 | 
			
		||||
  modelValue: boolean
 | 
			
		||||
  formInitValue?: Recordable & Partial<typeof initParams>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const props = withDefaults(defineProps<Props>(), {
 | 
			
		||||
  deptOptions: () => [],
 | 
			
		||||
  postOptions: () => [],
 | 
			
		||||
  modelValue: false,
 | 
			
		||||
  formInitValue: () => ({})
 | 
			
		||||
})
 | 
			
		||||
const emits = defineEmits(['update:modelValue', 'success'])
 | 
			
		||||
 | 
			
		||||
const { t } = useI18n() // 国际化
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
// 弹出层标题
 | 
			
		||||
const title = computed(() => {
 | 
			
		||||
  return formData.value?.id ? '修改用户' : '添加用户'
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 性别字典
 | 
			
		||||
const sexDictDatas = getDictOptions(DICT_TYPE.SYSTEM_USER_SEX)
 | 
			
		||||
 | 
			
		||||
// 表单初始化参数
 | 
			
		||||
const initParams = {
 | 
			
		||||
  nickname: '',
 | 
			
		||||
  deptId: '',
 | 
			
		||||
  mobile: '',
 | 
			
		||||
  email: '',
 | 
			
		||||
  id: undefined,
 | 
			
		||||
  username: '',
 | 
			
		||||
  password: '',
 | 
			
		||||
  sex: 1,
 | 
			
		||||
  postIds: [],
 | 
			
		||||
  remark: '',
 | 
			
		||||
  status: '0',
 | 
			
		||||
  roleIds: []
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 校验规则
 | 
			
		||||
const rules = {
 | 
			
		||||
  username: [{ required: true, message: '用户名称不能为空', trigger: 'blur' }],
 | 
			
		||||
  nickname: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
 | 
			
		||||
  password: [{ required: true, message: '用户密码不能为空', trigger: 'blur' }],
 | 
			
		||||
  email: [
 | 
			
		||||
    {
 | 
			
		||||
      type: 'email',
 | 
			
		||||
      message: "'请输入正确的邮箱地址",
 | 
			
		||||
      trigger: ['blur', 'change']
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  mobile: [
 | 
			
		||||
    {
 | 
			
		||||
      pattern: /^(?:(?:\+|00)86)?1(?:3[\d]|4[5-79]|5[0-35-9]|6[5-7]|7[0-8]|8[\d]|9[189])\d{8}$/,
 | 
			
		||||
      message: '请输入正确的手机号码',
 | 
			
		||||
      trigger: 'blur'
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
} as Partial<Record<string, Arrayable<FormItemRule>>>
 | 
			
		||||
const formRef = ref<Form | null>()
 | 
			
		||||
const formData = ref<Recordable>({ ...initParams })
 | 
			
		||||
watch(
 | 
			
		||||
  () => props.formInitValue,
 | 
			
		||||
  (val) => {
 | 
			
		||||
    formData.value = { ...val }
 | 
			
		||||
  },
 | 
			
		||||
  { deep: true }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const resetForm = () => {
 | 
			
		||||
  let form = formRef?.value
 | 
			
		||||
  if (!form) return
 | 
			
		||||
  formData.value = { ...initParams }
 | 
			
		||||
  form && (form as Form).resetFields()
 | 
			
		||||
}
 | 
			
		||||
const closeDialog = () => {
 | 
			
		||||
  emits('update:modelValue', false)
 | 
			
		||||
}
 | 
			
		||||
// 操作成功
 | 
			
		||||
const operateOk = () => {
 | 
			
		||||
  emits('success', true)
 | 
			
		||||
  closeDialog()
 | 
			
		||||
}
 | 
			
		||||
const submitForm = () => {
 | 
			
		||||
  let form = formRef.value as Form
 | 
			
		||||
  form.validate(async (valid) => {
 | 
			
		||||
    let data = formData.value
 | 
			
		||||
    if (valid) {
 | 
			
		||||
      try {
 | 
			
		||||
        if (data?.id !== undefined) {
 | 
			
		||||
          await updateUserApi(data)
 | 
			
		||||
          message.success(t('common.updateSuccess'))
 | 
			
		||||
          operateOk()
 | 
			
		||||
        } else {
 | 
			
		||||
          await createUserApi(data)
 | 
			
		||||
          message.success(t('common.createSuccess'))
 | 
			
		||||
          operateOk()
 | 
			
		||||
        }
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        console.error(err)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
  closeDialog()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
defineExpose({
 | 
			
		||||
  resetForm
 | 
			
		||||
})
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										153
									
								
								src/views/system/user/ImportForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/views/system/user/ImportForm.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-dialog
 | 
			
		||||
    :title="upload.title"
 | 
			
		||||
    :modelValue="modelValue"
 | 
			
		||||
    width="400px"
 | 
			
		||||
    append-to-body
 | 
			
		||||
    @close="closeDialog"
 | 
			
		||||
  >
 | 
			
		||||
    <el-upload
 | 
			
		||||
      ref="uploadRef"
 | 
			
		||||
      accept=".xlsx, .xls"
 | 
			
		||||
      :limit="1"
 | 
			
		||||
      :headers="upload.headers"
 | 
			
		||||
      :action="upload.url + '?updateSupport=' + upload.updateSupport"
 | 
			
		||||
      :disabled="upload.isUploading"
 | 
			
		||||
      :on-progress="handleFileUploadProgress"
 | 
			
		||||
      :on-success="handleFileSuccess"
 | 
			
		||||
      :on-exceed="handleExceed"
 | 
			
		||||
      :on-error="excelUploadError"
 | 
			
		||||
      :auto-upload="false"
 | 
			
		||||
      drag
 | 
			
		||||
    >
 | 
			
		||||
      <Icon icon="ep:upload" />
 | 
			
		||||
      <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
 | 
			
		||||
      <template #tip>
 | 
			
		||||
        <div class="el-upload__tip text-center">
 | 
			
		||||
          <div class="el-upload__tip">
 | 
			
		||||
            <el-checkbox v-model="upload.updateSupport" /> 是否更新已经存在的用户数据
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <span>仅允许导入xls、xlsx格式文件。</span>
 | 
			
		||||
          <el-link
 | 
			
		||||
            type="primary"
 | 
			
		||||
            :underline="false"
 | 
			
		||||
            style="font-size: 12px; vertical-align: baseline"
 | 
			
		||||
            @click="importTemplate"
 | 
			
		||||
            >下载模板</el-link
 | 
			
		||||
          >
 | 
			
		||||
        </div>
 | 
			
		||||
      </template>
 | 
			
		||||
    </el-upload>
 | 
			
		||||
    <template #footer>
 | 
			
		||||
      <div class="dialog-footer">
 | 
			
		||||
        <el-button type="primary" @click="submitFileForm">确 定</el-button>
 | 
			
		||||
        <el-button @click="cancel">取 消</el-button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
  </el-dialog>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { importUserTemplateApi } from '@/api/system/user'
 | 
			
		||||
import { getAccessToken, getTenantId } from '@/utils/auth'
 | 
			
		||||
import download from '@/utils/download'
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  modelValue: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// const props =
 | 
			
		||||
withDefaults(defineProps<Props>(), {
 | 
			
		||||
  modelValue: false
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
const emits = defineEmits(['update:modelValue', 'success'])
 | 
			
		||||
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
 | 
			
		||||
const uploadRef = ref()
 | 
			
		||||
 | 
			
		||||
// 用户导入参数
 | 
			
		||||
const upload = reactive({
 | 
			
		||||
  // // 是否显示弹出层(用户导入)
 | 
			
		||||
  // open: false,
 | 
			
		||||
  // 弹出层标题(用户导入)
 | 
			
		||||
  title: '用户导入',
 | 
			
		||||
  // 是否禁用上传
 | 
			
		||||
  isUploading: false,
 | 
			
		||||
  // 是否更新已经存在的用户数据
 | 
			
		||||
  updateSupport: 0,
 | 
			
		||||
  // 设置上传的请求头部
 | 
			
		||||
  headers: {
 | 
			
		||||
    Authorization: 'Bearer ' + getAccessToken(),
 | 
			
		||||
    'tenant-id': getTenantId()
 | 
			
		||||
  },
 | 
			
		||||
  // 上传的地址
 | 
			
		||||
  url: import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/system/user/import'
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
// 文件上传中处理
 | 
			
		||||
const handleFileUploadProgress = () => {
 | 
			
		||||
  upload.isUploading = true
 | 
			
		||||
}
 | 
			
		||||
// 文件上传成功处理
 | 
			
		||||
const handleFileSuccess = (response: any) => {
 | 
			
		||||
  if (response.code !== 0) {
 | 
			
		||||
    message.error(response.msg)
 | 
			
		||||
    return
 | 
			
		||||
  }
 | 
			
		||||
  upload.isUploading = false
 | 
			
		||||
  uploadRef.value?.clearFiles()
 | 
			
		||||
  // 拼接提示语
 | 
			
		||||
  const data = response.data
 | 
			
		||||
  let text = '上传成功数量:' + data.createUsernames.length + ';'
 | 
			
		||||
  for (let username of data.createUsernames) {
 | 
			
		||||
    text += '< ' + username + ' >'
 | 
			
		||||
  }
 | 
			
		||||
  text += '更新成功数量:' + data.updateUsernames.length + ';'
 | 
			
		||||
  for (const username of data.updateUsernames) {
 | 
			
		||||
    text += '< ' + username + ' >'
 | 
			
		||||
  }
 | 
			
		||||
  text += '更新失败数量:' + Object.keys(data.failureUsernames).length + ';'
 | 
			
		||||
  for (const username in data.failureUsernames) {
 | 
			
		||||
    text += '< ' + username + ': ' + data.failureUsernames[username] + ' >'
 | 
			
		||||
  }
 | 
			
		||||
  message.alert(text)
 | 
			
		||||
  emits('success')
 | 
			
		||||
  closeDialog()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 文件数超出提示
 | 
			
		||||
const handleExceed = (): void => {
 | 
			
		||||
  message.error('最多只能上传一个文件!')
 | 
			
		||||
}
 | 
			
		||||
// 上传错误提示
 | 
			
		||||
const excelUploadError = (): void => {
 | 
			
		||||
  message.error('导入数据失败,请您重新上传!')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** 下载模板操作 */
 | 
			
		||||
const importTemplate = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    const res = await importUserTemplateApi()
 | 
			
		||||
    download.excel(res, '用户导入模版.xls')
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 弹框按钮操作 */
 | 
			
		||||
// 点击取消
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
  closeDialog()
 | 
			
		||||
}
 | 
			
		||||
// 关闭弹窗
 | 
			
		||||
const closeDialog = () => {
 | 
			
		||||
  emits('update:modelValue', false)
 | 
			
		||||
}
 | 
			
		||||
// 提交上传文件
 | 
			
		||||
const submitFileForm = () => {
 | 
			
		||||
  uploadRef.value?.submit()
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										90
									
								
								src/views/system/user/RoleForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/views/system/user/RoleForm.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-dialog title="分配角色" :modelValue="show" width="500px" append-to-body @close="closeDialog">
 | 
			
		||||
    <el-form :model="formData" label-width="80px" ref="formRef">
 | 
			
		||||
      <el-form-item label="用户名称">
 | 
			
		||||
        <el-input v-model="formData.username" :disabled="true" />
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="用户昵称">
 | 
			
		||||
        <el-input v-model="formData.nickname" :disabled="true" />
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item label="角色">
 | 
			
		||||
        <el-select v-model="formData.roleIds" multiple placeholder="请选择">
 | 
			
		||||
          <el-option
 | 
			
		||||
            v-for="item in roleOptions"
 | 
			
		||||
            :key="parseInt(item.id)"
 | 
			
		||||
            :label="item.name"
 | 
			
		||||
            :value="parseInt(item.id)"
 | 
			
		||||
          />
 | 
			
		||||
        </el-select>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
    </el-form>
 | 
			
		||||
    <template #footer>
 | 
			
		||||
      <div class="dialog-footer">
 | 
			
		||||
        <el-button type="primary" @click="submit">确 定</el-button>
 | 
			
		||||
        <el-button @click="cancel">取 消</el-button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
  </el-dialog>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { assignUserRoleApi, PermissionAssignUserRoleReqVO } from '@/api/system/permission'
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  show: boolean
 | 
			
		||||
  roleOptions: any[]
 | 
			
		||||
  formInitValue?: Recordable & Partial<typeof initParams>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const props = withDefaults(defineProps<Props>(), {
 | 
			
		||||
  show: false,
 | 
			
		||||
  roleOptions: () => [],
 | 
			
		||||
  formInitValue: () => ({})
 | 
			
		||||
})
 | 
			
		||||
const emits = defineEmits(['update:show', 'success'])
 | 
			
		||||
 | 
			
		||||
const { t } = useI18n() // 国际化
 | 
			
		||||
const message = useMessage() // 消息弹窗
 | 
			
		||||
 | 
			
		||||
// 表单初始化参数
 | 
			
		||||
const initParams = {
 | 
			
		||||
  nickname: '',
 | 
			
		||||
  id: 0,
 | 
			
		||||
  username: '',
 | 
			
		||||
  roleIds: [] as number[]
 | 
			
		||||
}
 | 
			
		||||
const formData = ref<Recordable>({ ...initParams })
 | 
			
		||||
watch(
 | 
			
		||||
  () => props.formInitValue,
 | 
			
		||||
  (val) => {
 | 
			
		||||
    formData.value = { ...val }
 | 
			
		||||
  },
 | 
			
		||||
  { deep: true }
 | 
			
		||||
)
 | 
			
		||||
/* 弹框按钮操作 */
 | 
			
		||||
// 点击取消
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
  closeDialog()
 | 
			
		||||
}
 | 
			
		||||
// 关闭弹窗
 | 
			
		||||
const closeDialog = () => {
 | 
			
		||||
  emits('update:show', false)
 | 
			
		||||
}
 | 
			
		||||
// 提交
 | 
			
		||||
const submit = async () => {
 | 
			
		||||
  const data = ref<PermissionAssignUserRoleReqVO>({
 | 
			
		||||
    userId: formData.value.id,
 | 
			
		||||
    roleIds: formData.value.roleIds
 | 
			
		||||
  })
 | 
			
		||||
  try {
 | 
			
		||||
    await assignUserRoleApi(data.value)
 | 
			
		||||
    message.success(t('common.updateSuccess'))
 | 
			
		||||
    emits('success', true)
 | 
			
		||||
    closeDialog()
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    console.error(error)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style></style>
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,137 +0,0 @@
 | 
			
		||||
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],
 | 
			
		||||
  nickname: [required],
 | 
			
		||||
  password: [required],
 | 
			
		||||
  deptId: [required],
 | 
			
		||||
  email: [
 | 
			
		||||
    { required: true, message: t('profile.rules.mail'), trigger: 'blur' },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'email',
 | 
			
		||||
      message: t('profile.rules.truemail'),
 | 
			
		||||
      trigger: ['blur', 'change']
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  status: [required],
 | 
			
		||||
  mobile: [
 | 
			
		||||
    required,
 | 
			
		||||
    {
 | 
			
		||||
      len: 11,
 | 
			
		||||
      trigger: 'blur',
 | 
			
		||||
      message: '请输入正确的手机号码'
 | 
			
		||||
    },
 | 
			
		||||
    { validator: validateMobile, trigger: 'blur' }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
// crudSchemas
 | 
			
		||||
const crudSchemas = reactive<VxeCrudSchema>({
 | 
			
		||||
  primaryKey: 'id',
 | 
			
		||||
  primaryType: 'id',
 | 
			
		||||
  primaryTitle: '用户编号',
 | 
			
		||||
  action: true,
 | 
			
		||||
  actionWidth: '200px',
 | 
			
		||||
  columns: [
 | 
			
		||||
    {
 | 
			
		||||
      title: '用户账号',
 | 
			
		||||
      field: 'username',
 | 
			
		||||
      isSearch: true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '用户密码',
 | 
			
		||||
      field: 'password',
 | 
			
		||||
      isDetail: false,
 | 
			
		||||
      isTable: false,
 | 
			
		||||
      form: {
 | 
			
		||||
        component: 'InputPassword'
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '用户' + t('profile.user.sex'),
 | 
			
		||||
      field: 'sex',
 | 
			
		||||
      dictType: DICT_TYPE.SYSTEM_USER_SEX,
 | 
			
		||||
      dictClass: 'number',
 | 
			
		||||
      table: { show: false }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '用户昵称',
 | 
			
		||||
      field: 'nickname'
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '用户邮箱',
 | 
			
		||||
      field: 'email'
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '手机号码',
 | 
			
		||||
      field: 'mobile',
 | 
			
		||||
      isSearch: true
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '部门',
 | 
			
		||||
      field: 'deptId',
 | 
			
		||||
      isTable: false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '岗位',
 | 
			
		||||
      field: 'postIds',
 | 
			
		||||
      isTable: false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: t('common.status'),
 | 
			
		||||
      field: 'status',
 | 
			
		||||
      dictType: DICT_TYPE.COMMON_STATUS,
 | 
			
		||||
      dictClass: 'number',
 | 
			
		||||
      isSearch: true,
 | 
			
		||||
      table: {
 | 
			
		||||
        slots: {
 | 
			
		||||
          default: 'status_default'
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '最后登录时间',
 | 
			
		||||
      field: 'loginDate',
 | 
			
		||||
      formatter: 'formatDate',
 | 
			
		||||
      isForm: false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: '最后登录IP',
 | 
			
		||||
      field: 'loginIp',
 | 
			
		||||
      isTable: false,
 | 
			
		||||
      isForm: false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: t('form.remark'),
 | 
			
		||||
      field: 'remark',
 | 
			
		||||
      isTable: false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      title: t('common.createTime'),
 | 
			
		||||
      field: 'createTime',
 | 
			
		||||
      formatter: 'formatDate',
 | 
			
		||||
      isTable: false,
 | 
			
		||||
      isForm: false,
 | 
			
		||||
      search: {
 | 
			
		||||
        show: true,
 | 
			
		||||
        itemRender: {
 | 
			
		||||
          name: 'XDataTimePicker'
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
export const { allSchemas } = useVxeCrudSchemas(crudSchemas)
 | 
			
		||||
							
								
								
									
										44
									
								
								src/views/system/user/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/views/system/user/utils.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
export const parseTime = (time) => {
 | 
			
		||||
  if (!time) {
 | 
			
		||||
    return null
 | 
			
		||||
  }
 | 
			
		||||
  const format = '{y}-{m}-{d} {h}:{i}:{s}'
 | 
			
		||||
  let date
 | 
			
		||||
  if (typeof time === 'object') {
 | 
			
		||||
    date = time
 | 
			
		||||
  } else {
 | 
			
		||||
    if (typeof time === 'string' && /^[0-9]+$/.test(time)) {
 | 
			
		||||
      time = parseInt(time)
 | 
			
		||||
    } else if (typeof time === 'string') {
 | 
			
		||||
      time = time
 | 
			
		||||
        .replace(new RegExp(/-/gm), '/')
 | 
			
		||||
        .replace('T', ' ')
 | 
			
		||||
        .replace(new RegExp(/\.[\d]{3}/gm), '')
 | 
			
		||||
    }
 | 
			
		||||
    if (typeof time === 'number' && time.toString().length === 10) {
 | 
			
		||||
      time = time * 1000
 | 
			
		||||
    }
 | 
			
		||||
    date = new Date(time)
 | 
			
		||||
  }
 | 
			
		||||
  const formatObj = {
 | 
			
		||||
    y: date.getFullYear(),
 | 
			
		||||
    m: date.getMonth() + 1,
 | 
			
		||||
    d: date.getDate(),
 | 
			
		||||
    h: date.getHours(),
 | 
			
		||||
    i: date.getMinutes(),
 | 
			
		||||
    s: date.getSeconds(),
 | 
			
		||||
    a: date.getDay()
 | 
			
		||||
  }
 | 
			
		||||
  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
 | 
			
		||||
    let value = formatObj[key]
 | 
			
		||||
    // Note: getDay() returns 0 on Sunday
 | 
			
		||||
    if (key === 'a') {
 | 
			
		||||
      return ['日', '一', '二', '三', '四', '五', '六'][value]
 | 
			
		||||
    }
 | 
			
		||||
    if (result.length > 0 && value < 10) {
 | 
			
		||||
      value = '0' + value
 | 
			
		||||
    }
 | 
			
		||||
    return value || 0
 | 
			
		||||
  })
 | 
			
		||||
  return time_str
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user