user-edit.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. <script setup lang="ts">
  2. import { reactive, ref, computed } from "vue";
  3. import * as $userApi from "@/api/sys/user";
  4. import message from "@/utils/message";
  5. const formRef = ref();
  6. const checkUsername = (rule: any, value: any, callback: any) => {
  7. if (value === "") {
  8. callback(new Error("请输入帐号"));
  9. } else {
  10. if (pageData.mode === "add") {
  11. $userApi.hashUsername(value).then((res: any) => {
  12. if (res.success) {
  13. if (res.result) {
  14. callback(new Error("帐号已存在,请重新输入"));
  15. } else {
  16. callback();
  17. }
  18. } else {
  19. callback(new Error("帐号已存在,请重新输入"));
  20. }
  21. });
  22. }
  23. }
  24. };
  25. const validatePass2 = (rule: any, value: any, callback: any) => {
  26. if (value === "") {
  27. callback(new Error("请再次输入密码"));
  28. } else if (value !== pageData.formParam.infoForm.password) {
  29. callback(new Error("两次输入密码不正确"));
  30. } else {
  31. callback();
  32. }
  33. };
  34. const pageData: any = reactive({
  35. mode: "add",
  36. modalParam: {
  37. visible: false,
  38. title: "用户新增",
  39. closeOnclickModal: true
  40. },
  41. formParam: {
  42. formFields: [
  43. {
  44. type: "input",
  45. label: "帐号",
  46. prop: "username",
  47. placeholder: "请输入帐号"
  48. },
  49. {
  50. type: "input",
  51. label: "姓名",
  52. prop: "nickname",
  53. placeholder: "请输入姓名"
  54. },
  55. {
  56. type: "input",
  57. label: "密码",
  58. prop: "password",
  59. placeholder: "请输入密码",
  60. options: {
  61. type: "password",
  62. showPassword: true
  63. }
  64. },
  65. {
  66. type: "input",
  67. label: "确认密码",
  68. prop: "confirmPassword",
  69. placeholder: "请输入确认密码",
  70. options: {
  71. type: "password",
  72. showPassword: true
  73. }
  74. },
  75. {
  76. type: "select",
  77. label: "分配角色",
  78. prop: "roleIds",
  79. placeholder: "请选择分配角色",
  80. dataSourceKey: "roleList",
  81. options: {
  82. filterable: true,
  83. multiple: true,
  84. keys: {
  85. prop: "id",
  86. value: "id",
  87. label: "roleName"
  88. }
  89. }
  90. },
  91. {
  92. type: "select",
  93. label: "状态",
  94. prop: "enable",
  95. placeholder: "请选择",
  96. dataSourceKey: "enabledOptions",
  97. options: {
  98. keys: {
  99. label: "label",
  100. value: "value",
  101. prop: "value"
  102. },
  103. filterable: true
  104. }
  105. }
  106. ],
  107. infoForm: {},
  108. rules: {
  109. orgId: [{ required: true, message: "请选择所属机构", trigger: "change" }],
  110. username: [
  111. { required: true, message: "请输入帐号", trigger: "blur" },
  112. { min: 4, max: 20, message: "长度在 4 到 20 个字符", trigger: "blur" },
  113. { validator: checkUsername, trigger: "blur" },
  114. {
  115. pattern: /^[a-zA-Z0-9]{4,20}$/,
  116. message: "只能输入4-20个字母、数字",
  117. trigger: "blur"
  118. }
  119. ],
  120. nickname: [
  121. { required: true, message: "请输入姓名", trigger: "blur" },
  122. { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  123. ],
  124. enable: [{ required: true, message: "请选择状态", trigger: "change" }],
  125. password: [
  126. { required: true, message: "请输入密码", trigger: "blur" },
  127. { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }
  128. ],
  129. confirmPassword: [
  130. { required: true, message: "请输入确认密码", trigger: "blur" },
  131. { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" },
  132. { validator: validatePass2, trigger: "blur" }
  133. ]
  134. },
  135. loading: false
  136. },
  137. dataSource: {
  138. enabledOptions: [],
  139. roleList: []
  140. }
  141. });
  142. const showFormItem = computed(() => (item: any) => {
  143. if (pageData.mode === "add") {
  144. return true;
  145. }
  146. return item.prop !== "confirmPassword" && item.prop !== "password";
  147. });
  148. const formFields = computed(() => {
  149. const fields: any[] = [
  150. {
  151. type: "input",
  152. label: "帐号",
  153. prop: "username",
  154. placeholder: "请输入帐号"
  155. },
  156. {
  157. type: "input",
  158. label: "姓名",
  159. prop: "nickname",
  160. placeholder: "请输入姓名"
  161. },
  162. {
  163. type: "select",
  164. label: "分配角色",
  165. prop: "roleIds",
  166. placeholder: "请选择分配角色",
  167. dataSourceKey: "roleList",
  168. options: {
  169. filterable: true,
  170. multiple: true,
  171. keys: {
  172. prop: "id",
  173. value: "id",
  174. label: "roleName"
  175. }
  176. }
  177. },
  178. {
  179. type: "select",
  180. label: "状态",
  181. prop: "enable",
  182. placeholder: "请选择",
  183. dataSourceKey: "enabledOptions",
  184. options: {
  185. keys: {
  186. label: "label",
  187. value: "value",
  188. prop: "value"
  189. },
  190. filterable: true
  191. }
  192. }
  193. ];
  194. if (pageData.mode === "add") {
  195. fields.splice(
  196. 3,
  197. 0,
  198. {
  199. type: "input",
  200. label: "密码",
  201. prop: "password",
  202. placeholder: "请输入密码",
  203. options: {
  204. type: "password",
  205. showPassword: true
  206. }
  207. },
  208. {
  209. type: "input",
  210. label: "确认密码",
  211. prop: "confirmPassword",
  212. placeholder: "请输入确认密码",
  213. options: {
  214. type: "password",
  215. showPassword: true
  216. }
  217. }
  218. );
  219. }
  220. return fields;
  221. });
  222. const formRules = computed(() => {
  223. const rule: any = {
  224. orgId: [{ required: true, message: "请选择所属机构", trigger: "change" }],
  225. username: [
  226. { required: true, message: "请输入帐号", trigger: "blur" },
  227. { min: 4, max: 20, message: "长度在 4 到 20 个字符", trigger: "blur" },
  228. {
  229. pattern: /^[a-zA-Z0-9]{4,20}$/,
  230. message: "只能输入4-20个字母、数字",
  231. trigger: "blur"
  232. }
  233. ],
  234. nickname: [
  235. { required: true, message: "请输入姓名", trigger: "blur" },
  236. { min: 2, max: 20, message: "长度在 2 到 20 个字符", trigger: "blur" }
  237. ],
  238. enable: [{ required: true, message: "请选择状态", trigger: "change" }]
  239. };
  240. if (pageData.mode === "add") {
  241. rule["password"] = [
  242. { required: true, message: "请输入密码", trigger: "blur" },
  243. { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }
  244. ];
  245. rule["confirmPassword"] = [
  246. { required: true, message: "请输入确认密码", trigger: "blur" },
  247. { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" },
  248. { validator: validatePass2, trigger: "blur" }
  249. ];
  250. rule.username.push({
  251. validator: checkUsername,
  252. trigger: "blur"
  253. });
  254. }
  255. return rule;
  256. });
  257. const disabledFields = computed(() => (item: any) => {
  258. if (pageData.mode === "add") {
  259. return false;
  260. }
  261. if (pageData.mode === "detail") {
  262. return true;
  263. }
  264. return item.prop === "orgId" || item.prop === "username";
  265. });
  266. const showBtn = computed(() => {
  267. if (pageData.mode === "detail") {
  268. return false;
  269. }
  270. return true;
  271. });
  272. const queryUserRoleId = () => {
  273. if (!pageData.formParam.infoForm.id) {
  274. return;
  275. }
  276. $userApi.queryRoleIds(pageData.formParam.infoForm.id).then((res: any) => {
  277. if (res.success) {
  278. pageData.formParam.infoForm.roleIds = res.result;
  279. }
  280. });
  281. };
  282. const open = (infoForm: any, dataSource: any, mode: string) => {
  283. pageData.mode = mode;
  284. pageData.formParam.infoForm = infoForm;
  285. pageData.dataSource = dataSource;
  286. if (mode !== "add") {
  287. queryUserRoleId();
  288. }
  289. if (mode === "edit") {
  290. pageData.modalParam.title = "会员编辑";
  291. }
  292. if (mode === "detail") {
  293. pageData.modalParam.closeOnclickModal = true;
  294. } else {
  295. pageData.modalParam.closeOnclickModal = false;
  296. }
  297. pageData.modalParam.visible = true;
  298. };
  299. const initData = () => {
  300. pageData.formParam.infoForm = { enable: 1 };
  301. pageData.formParam.loading = false;
  302. pageData.modalParam.closeOnclickModal = true;
  303. pageData.mode = "add";
  304. pageData.modalParam.visible = false;
  305. };
  306. const _handleClose = () => {
  307. initData();
  308. emits("close");
  309. };
  310. const handleCancel = () => {
  311. pageData.modalParam.visible = false;
  312. };
  313. const handleConfirm = () => {
  314. formRef.value!.validate((isValid: boolean) => {
  315. if (isValid) {
  316. if (pageData.mode === "add") {
  317. save();
  318. } else {
  319. update();
  320. }
  321. }
  322. });
  323. };
  324. const save = () => {
  325. pageData.formParam.loading = true;
  326. const params = pageData.formParam.infoForm;
  327. $userApi
  328. .save(params)
  329. .then((res: any) => {
  330. if (res.success) {
  331. initData();
  332. emits("confirm");
  333. message.success("保存成功");
  334. } else {
  335. message.error(res.message);
  336. }
  337. })
  338. .finally(() => {
  339. pageData.formParam.loading = false;
  340. });
  341. };
  342. const update = () => {
  343. pageData.formParam.loading = true;
  344. const params = pageData.formParam.infoForm;
  345. $userApi
  346. .update(params.id, params)
  347. .then((res: any) => {
  348. if (res.success) {
  349. initData();
  350. emits("confirm");
  351. message.success("保存成功");
  352. } else {
  353. message.error(res.message);
  354. }
  355. })
  356. .finally(() => {
  357. pageData.formParam.loading = false;
  358. });
  359. };
  360. defineOptions({
  361. name: "UserEdit"
  362. });
  363. const emits = defineEmits(["close", "confirm"]);
  364. defineExpose({ open });
  365. </script>
  366. <template>
  367. <div>
  368. <el-drawer
  369. v-model="pageData.modalParam.visible"
  370. :title="pageData.modalParam.title"
  371. destroy-on-close
  372. modal
  373. :close-on-click-modal="pageData.modalParam.closeOnclickModal"
  374. :before-close="_handleClose"
  375. >
  376. <template #header>
  377. <span style="font-weight: 700">{{ pageData.modalParam.title }}</span>
  378. </template>
  379. <el-form
  380. :model="pageData.formParam.infoForm"
  381. :rules="formRules"
  382. label-position="left"
  383. ref="formRef"
  384. v-loading="pageData.formParam.loading"
  385. >
  386. <el-form-item
  387. v-for="(item, index) in formFields"
  388. :label="item.label"
  389. :prop="item.prop"
  390. :key="index"
  391. class="form-row"
  392. v-show="showFormItem(item)"
  393. >
  394. <template v-if="item.type === 'input'">
  395. <el-input
  396. v-model="pageData.formParam.infoForm[item.prop]"
  397. clearable
  398. :type="item.options?.type ?? 'text'"
  399. :show-password="item.options?.showPassword ?? false"
  400. :disabled="disabledFields(item)"
  401. />
  402. </template>
  403. <template v-if="item.type === 'select'">
  404. <el-select
  405. style="width: 1000%"
  406. v-model="pageData.formParam.infoForm[item.prop]"
  407. :clearable="item.options?.clearable ?? false"
  408. :filterable="item.options?.filterable ?? false"
  409. :multiple="item.options?.multiple ?? false"
  410. :disabled="disabledFields(item)"
  411. >
  412. <el-option
  413. v-for="val in pageData.dataSource[item.dataSourceKey]"
  414. :label="val[item.options?.keys?.label ?? 'label']"
  415. :key="val[item.options?.keys?.value ?? 'value']"
  416. :value="val[item.options?.keys?.value ?? 'value']"
  417. />
  418. </el-select>
  419. </template>
  420. </el-form-item>
  421. </el-form>
  422. <template #footer>
  423. <el-popconfirm
  424. title="确定放弃编辑?"
  425. ok-text="确定"
  426. cancel-text="取消"
  427. @confirm="handleCancel"
  428. >
  429. <template #reference>
  430. <el-button v-show="showBtn" plain>取 消</el-button>
  431. </template>
  432. </el-popconfirm>
  433. <el-popconfirm
  434. title="确认提交?"
  435. @confirm="handleConfirm"
  436. confirm-button-text="确定"
  437. cancel-button-text="取消"
  438. >
  439. <template #reference>
  440. <el-button
  441. type="primary"
  442. plain
  443. v-show="showBtn"
  444. v-loading="pageData.formParam.loading"
  445. >提 交</el-button
  446. >
  447. </template>
  448. </el-popconfirm>
  449. </template>
  450. </el-drawer>
  451. </div>
  452. </template>