iot-ui-vue/src/views/system/User/components/EditUserDialog.vue

406 lines
14 KiB
Vue

<template>
<j-modal
visible
:title="dialogTitle"
width="675px"
@ok="confirm"
@cancel="emits('update:visible', false)"
class="edit-dialog-container"
:confirmLoading="loading"
cancelText="取消"
okText="确定"
>
<j-form ref="formRef" :model="form.data" layout="vertical">
<j-row :gutter="24" v-if="form.IsShow('add', 'edit')">
<j-col :span="12">
<j-form-item
name="name"
label="姓名"
:rules="[{ required: true, message: '请输入姓名' }]"
>
<j-input
v-model:value="form.data.name"
placeholder="请输入姓名"
/>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
name="username"
label="用户名"
:rules="[
{ required: true, message: '' },
{
validator: form.rules.checkUserName,
trigger: 'blur',
},
]"
>
<j-input
v-model:value="form.data.username"
placeholder="请输入用户名"
:disabled="props.type === 'edit'"
/>
</j-form-item>
</j-col>
</j-row>
<j-row v-if="form.IsShow('add', 'reset')">
<j-col :span="24">
<j-form-item
name="password"
label="密码"
:rules="[
{ required: true, message: '' },
{
validator: form.rules.checkPassword,
trigger: 'blur',
},
]"
>
<j-input-password
v-model:value="form.data.password"
placeholder="请输入密码"
/>
</j-form-item>
</j-col>
</j-row>
<j-row v-if="form.IsShow('add', 'reset')">
<j-col :span="24">
<j-form-item
name="confirmPassword"
label="确认密码"
:rules="[
{ required: true, message: '' },
{
validator: form.rules.checkAgainPassword,
trigger: 'blur',
},
]"
>
<j-input-password
v-model:value="form.data.confirmPassword"
placeholder="请再次输入密码"
:maxlength="64"
/>
</j-form-item>
</j-col>
</j-row>
<j-row :gutter="24" v-if="form.IsShow('add', 'edit')">
<j-col :span="12">
<j-form-item name="roleIdList" label="角色" class="flex">
<j-select
v-model:value="form.data.roleIdList"
mode="multiple"
style="width: 100%"
placeholder="请选择角色"
:options="form.roleOptions"
></j-select>
<PermissionButton
:hasPermission="`${rolePermission}:add`"
@click="form.clickAddItem('roleIdList', 'Role')"
>
<AIcon type="PlusOutlined" />
</PermissionButton>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item name="orgIdList" label="组织" class="flex">
<j-tree-select
v-model:value="form.data.orgIdList"
show-search
style="width: 100%"
placeholder="请选择组织"
multiple
:tree-data="form.departmentOptions"
:fieldNames="{ label: 'name', value: 'id' }"
>
<template #title="{ name }">
{{ name }}
</template>
</j-tree-select>
<PermissionButton
:hasPermission="`${deptPermission}:add`"
@click="
form.clickAddItem('orgIdList', 'Department')
"
>
<AIcon type="PlusOutlined" />
</PermissionButton>
</j-form-item>
</j-col>
</j-row>
<j-row :gutter="24" v-if="form.IsShow('add', 'edit')">
<j-col :span="12">
<j-form-item
name="telephone"
label="手机号"
:rules="[
{
pattern: /^1[3456789]\d{9}$/,
message: '请输入正确的手机号',
},
]"
>
<j-input
v-model:value="form.data.telephone"
placeholder="请输入手机号"
:maxlength="64"
/>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item
name="email"
label="邮箱"
:rules="[
{
pattern:
/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
message: '请输入正确的邮箱',
},
]"
>
<j-input
v-model:value="form.data.email"
placeholder="请输入邮箱"
:maxlength="64"
/>
</j-form-item>
</j-col>
</j-row>
</j-form>
</j-modal>
</template>
<script setup lang="ts">
import PermissionButton from '@/components/PermissionButton/index.vue';
import { FormInstance, message } from 'ant-design-vue';
import {
validateField_api,
getRoleList_api,
getDepartmentList_api,
addUser_api,
updateUser_api,
updatePassword_api,
getUser_api,
} from '@/api/system/user';
import { Rule } from 'ant-design-vue/es/form';
import { DefaultOptionType } from 'ant-design-vue/es/vc-tree-select/TreeSelect';
import { AxiosResponse } from 'axios';
const deptPermission = 'system/Department';
const rolePermission = 'system/Role';
const emits = defineEmits(['confirm', 'update:visible']);
const props = defineProps<{
type: modalType;
data: any;
visible: boolean;
}>();
// 弹窗相关
const loading = ref(false);
const dialogTitle = computed(() => {
if (props.type === 'add') return '新增';
else if (props.type === 'edit') return '编辑';
else if (props.type === 'reset') return '重置密码';
else return '';
});
const confirm = () => {
loading.value = true;
formRef.value
?.validate()
.then(() => form.submit())
.then((resp: any) => {
if (resp.status === 200) {
message.success('操作成功');
emits('confirm');
emits('update:visible', false);
}
})
.finally(() => (loading.value = false));
};
const formRef = ref<FormInstance>();
const form = reactive({
data: {} as formType,
rules: {
checkUserName: (_rule: Rule, value: string): Promise<any> =>
new Promise((resolve, reject) => {
if (props.type === 'edit') return resolve('');
if (!value) return reject('请输入用户名');
else if (value.length > 64) return reject('最多可输入64个字符');
validateField_api('username', value).then((resp: any): any => {
resp.result.passed
? resolve('')
: reject(resp.result.reason);
});
}),
checkPassword: (_rule: Rule, value: string): Promise<any> =>
new Promise((resolve, reject) => {
if (!value) return reject('请输入密码');
else if (value.length > 64) return reject('最多可输入64个字符');
else if (value.length < 8) return reject('密码不能少于8位');
validateField_api('password', value).then((resp: any) => {
resp.result.passed
? resolve('')
: reject(resp.result.reason);
});
}),
checkAgainPassword: (_rule: Rule, value: string): Promise<any> => {
if (!value) return Promise.reject('请输入8~64位的密码');
return value === form.data.password
? Promise.resolve()
: Promise.reject('两次密码输入不一致');
},
},
roleOptions: [] as optionType[],
departmentOptions: [] as DefaultOptionType[],
init: () => {
form.getDepartmentList();
form.getRoleList();
form.getUserInfo();
},
getUserInfo: () => {
const id = props.data.id || '';
console.log(111);
if (props.type === 'add') form.data = {} as formType;
else if (props.type === 'reset') form.data = { id } as formType;
else if (props.type === 'edit') {
getUser_api(id).then((resp: any) => {
form.data = {
...(resp.result as formType),
orgIdList: resp.result.orgList.map(
(item: dictType) => item.id,
),
roleIdList: resp.result.roleList.map(
(item: dictType) => item.id,
),
};
nextTick(() => {
formRef.value?.clearValidate();
});
});
}
},
submit: (): Promise<any> => {
let api: axiosFunType;
let params = {};
if (props.type === 'add') {
api = addUser_api;
params = {
user: form.data,
orgIdList: form.data.orgIdList,
roleIdList: form.data.roleIdList,
};
} else if (props.type === 'edit') {
api = updateUser_api;
params = {
id: form.data.id,
user: form.data,
orgIdList: form.data.orgIdList,
roleIdList: form.data.roleIdList,
};
} else if (props.type === 'reset') {
api = updatePassword_api;
params = {
id: form.data.id,
password: form.data.password,
};
} else return Promise.reject();
return api(params);
},
getRoleList: () => {
getRoleList_api().then((resp: any) => {
form.roleOptions = resp.result.map((item: dictType) => ({
label: item.name,
value: item.id,
}));
});
},
getDepartmentList: () => {
getDepartmentList_api().then((resp: any) => {
form.departmentOptions = resp.result;
});
},
IsShow: (...typeList: modalType[]) => typeList.includes(props.type),
clickAddItem: (prop: 'roleIdList' | 'orgIdList', target: string) => {
const tab: any = window.open(`${origin}/#/system/${target}?save=true`);
tab.onSaveSuccess = (value: string) => {
form.data[prop] = [...(form.data[prop] || []), value];
if (prop === 'roleIdList') form.getRoleList();
else form.getDepartmentList();
};
},
});
form.init();
interface AxiosResponseRewrite<T = any[]> extends AxiosResponse<T, any> {
result: T;
success: boolean;
}
type axiosFunType = (data: any) => Promise<AxiosResponseRewrite<unknown>>;
type modalType = '' | 'add' | 'edit' | 'reset';
type formType = {
id?: string;
name: string;
username: string;
password: string;
confirmPassword: string;
roleIdList: string[];
orgIdList: string[];
telephone: string;
email: string;
};
type dictType = {
id: string;
name: string;
children?: dictType;
};
type optionType = {
value: string;
label: string;
};
</script>
<style lang="less" scoped>
.edit-dialog-container {
.ant-form-item {
&.flex {
:deep(.ant-form-item-control-input-content) {
display: flex;
.ant-select {
flex: 1;
}
.ant-tooltip-disabled-compatible-wrapper {
.ant-btn {
color: rgba(0, 0, 0, 0.25);
border-color: #d9d9d9;
background: #f5f5f5;
text-shadow: none;
box-shadow: none;
}
}
.ant-btn {
width: 32px;
height: 32px;
border: 1px solid #1d39c4;
color: #1d39c4;
display: flex;
align-items: center;
justify-content: center;
margin-left: 8px;
cursor: pointer;
}
}
}
}
}
</style>