hook.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. import "./reset.css";
  2. import editForm from "../form/index.vue";
  3. import { zxcvbn } from "@zxcvbn-ts/core";
  4. import { message } from "@/utils/message";
  5. import { usePublicHooks } from "../../hooks";
  6. import { addDialog } from "@/components/ReDialog";
  7. import type { PaginationProps } from "@pureadmin/table";
  8. import type { FormItemProps } from "../utils/types";
  9. import {
  10. getKeyList,
  11. isAllEmpty,
  12. deviceDetection
  13. } from "@pureadmin/utils";
  14. import {
  15. getUserList,
  16. addUser,
  17. deleteUser,
  18. modifyUser
  19. } from "@/api/system";
  20. import {
  21. ElForm,
  22. ElInput,
  23. ElFormItem,
  24. ElProgress,
  25. ElMessageBox
  26. } from "element-plus";
  27. import {
  28. type Ref,
  29. h,
  30. ref,
  31. toRaw,
  32. watch,
  33. computed,
  34. reactive,
  35. onMounted
  36. } from "vue";
  37. import { ROLES } from '@/global/constDefine'
  38. export function useUser(tableRef: Ref, treeRef: Ref) {
  39. const form = reactive({
  40. // 左侧部门树的id
  41. deptId: "",
  42. username: "",
  43. phone: "",
  44. status: ""
  45. });
  46. const editMap = ref({});
  47. const formRef = ref();
  48. const ruleFormRef = ref();
  49. const dataList = ref([]);
  50. const loading = ref(true);
  51. const switchLoadMap = ref({});
  52. const { switchStyle } = usePublicHooks();
  53. const selectedNum = ref(0);
  54. const pagination = reactive<PaginationProps>({
  55. total: 0,
  56. pageSize: 10,
  57. currentPage: 1,
  58. background: true
  59. });
  60. const columns: TableColumnList = [
  61. {
  62. label: "用户名称",
  63. prop: "username",
  64. minWidth: 130,
  65. cellRenderer: ({ row, index }) => (
  66. <>
  67. {editMap.value[index]?.editable ? (
  68. <el-input v-model={row.username} />
  69. ) : (
  70. <p>{row.username}</p>
  71. )}
  72. </>
  73. )
  74. },
  75. {
  76. label: "用户昵称",
  77. prop: "nickname",
  78. minWidth: 130,
  79. cellRenderer: ({ row, index }) => (
  80. <>
  81. {editMap.value[index]?.editable ? (
  82. <el-input v-model={row.nickname} />
  83. ) : (
  84. <p>{row.nickname}</p>
  85. )}
  86. </>
  87. )
  88. },
  89. {
  90. label: "角色",
  91. prop: "roles",
  92. minWidth: 130,
  93. cellRenderer: ({ row, index }) => (
  94. <div>
  95. {
  96. row.roles.map((curname) => {
  97. // const matchedObj = ROLES.find(obj => { obj.name == curname });
  98. // console.log('matchedObj', matchedObj);
  99. return <el-tag > {
  100. ROLES.find(obj => { if (obj.name == curname) return obj })?.title
  101. } </el-tag>;
  102. })
  103. }
  104. </div>
  105. )
  106. },
  107. // {
  108. // label: "密码",
  109. // prop: "password",
  110. // minWidth: 130,
  111. // cellRenderer: ({ row, index }) => (
  112. // <>
  113. // {editMap.value[index]?.editable ? (
  114. // <el-input v-model={row.id} />
  115. // ) : (
  116. // <p>{row.id}</p>
  117. // )}
  118. // </>
  119. // )
  120. // },
  121. // {
  122. // label: "确认密码",
  123. // prop: "password2",
  124. // minWidth: 130,
  125. // cellRenderer: ({ row, index }) => (
  126. // <>
  127. // {editMap.value[index]?.editable ? (
  128. // <el-input v-model={row.id} />
  129. // ) : (
  130. // <p>{row.id}</p>
  131. // )}
  132. // </>
  133. // )
  134. // },
  135. {
  136. label: "状态",
  137. prop: "status",
  138. minWidth: 90,
  139. cellRenderer: scope => (
  140. <el-switch
  141. size={scope.props.size === "small" ? "small" : "default"}
  142. loading={switchLoadMap.value[scope.index]?.loading}
  143. v-model={scope.row.status}
  144. active-value={1}
  145. inactive-value={0}
  146. active-text="已启用"
  147. inactive-text="已停用"
  148. inline-prompt
  149. style={switchStyle.value}
  150. onChange={() => onChange(scope as any)}
  151. />
  152. )
  153. },
  154. {
  155. label: "操作",
  156. fixed: "right",
  157. width: 180,
  158. slot: "operation"
  159. }
  160. ];
  161. const buttonClass = computed(() => {
  162. return [
  163. "h-[20px]!",
  164. "reset-margin",
  165. "text-gray-500!",
  166. "dark:text-white!",
  167. "dark:hover:text-primary!"
  168. ];
  169. });
  170. // 重置的新密码
  171. const pwdForm = reactive({
  172. newPwd: ""
  173. });
  174. const pwdProgress = [
  175. { color: "#e74242", text: "非常弱" },
  176. { color: "#EFBD47", text: "弱" },
  177. { color: "#ffa500", text: "一般" },
  178. { color: "#1bbf1b", text: "强" },
  179. { color: "#008000", text: "非常强" }
  180. ];
  181. // 当前密码强度(0-4)
  182. const curScore = ref();
  183. const roleOptions = ref([]);
  184. function onChange({ row, index }) {
  185. ElMessageBox.confirm(
  186. `确认要<strong>${
  187. row.status === 0 ? "停用" : "启用"
  188. }</strong><strong style='color:var(--el-color-primary)'>${
  189. row.username
  190. }</strong>用户吗?`,
  191. "系统提示",
  192. {
  193. confirmButtonText: "确定",
  194. cancelButtonText: "取消",
  195. type: "warning",
  196. dangerouslyUseHTMLString: true,
  197. draggable: true
  198. }
  199. )
  200. .then(() => {
  201. switchLoadMap.value[index] = Object.assign(
  202. {},
  203. switchLoadMap.value[index],
  204. {
  205. loading: true
  206. }
  207. );
  208. modifyUser({ user: row }).then((resp) => {
  209. switchLoadMap.value[index] = Object.assign(
  210. {},
  211. switchLoadMap.value[index],
  212. {
  213. loading: false
  214. }
  215. );
  216. if (resp.success) {
  217. message("已成功修改用户状态", {
  218. type: "success"
  219. });
  220. onSearch();
  221. } else {
  222. message("修改用户状态失败", {
  223. type: "info"
  224. });
  225. }
  226. });
  227. })
  228. .catch(() => {
  229. row.status === 0 ? (row.status = 1) : (row.status = 0);
  230. });
  231. }
  232. function handleUpdate(row) {
  233. console.log(row);
  234. }
  235. function handleDelete(row) {
  236. deleteUser({ username: row.username }).then((resp) => {
  237. if (resp.success) {
  238. message(`您删除了用户名为${row.username}的这条数据`, { type: "success" });
  239. onSearch();
  240. } else {
  241. message(`删除用户名为${row.username}的这条数据失败`, { type: "info" });
  242. }
  243. });
  244. }
  245. function handleSizeChange(val: number) {
  246. console.log(`${val} items per page`);
  247. }
  248. function handleCurrentChange(val: number) {
  249. console.log(`current page: ${val}`);
  250. }
  251. /** 当CheckBox选择项发生变化时会触发该事件 */
  252. function handleSelectionChange(val) {
  253. selectedNum.value = val.length;
  254. // 重置表格高度
  255. tableRef.value.setAdaptive();
  256. }
  257. /** 取消选择 */
  258. function onSelectionCancel() {
  259. selectedNum.value = 0;
  260. // 用于多选表格,清空用户的选择
  261. tableRef.value.getTableRef().clearSelection();
  262. }
  263. /** 批量删除 */
  264. function onbatchDel() {
  265. // 返回当前选中的行
  266. const curSelected = tableRef.value.getTableRef().getSelectionRows();
  267. // 接下来根据实际业务,通过选中行的某项数据,比如下面的id,调用接口进行批量删除
  268. message(`已删除用户编号为 ${getKeyList(curSelected, "id")} 的数据`, {
  269. type: "success"
  270. });
  271. tableRef.value.getTableRef().clearSelection();
  272. onSearch();
  273. }
  274. async function onSearch() {
  275. loading.value = true;
  276. console.log('getUserList');
  277. const { items } = await getUserList(toRaw(form));
  278. dataList.value = items;
  279. pagination.total = items.length;
  280. // pagination.pageSize = data.pageSize;
  281. // pagination.currentPage = data.currentPage;
  282. setTimeout(() => {
  283. loading.value = false;
  284. }, 500);
  285. }
  286. const resetForm = formEl => {
  287. if (!formEl) return;
  288. formEl.resetFields();
  289. form.deptId = "";
  290. treeRef.value.onTreeReset();
  291. onSearch();
  292. };
  293. function onTreeSelect({ id, selected }) {
  294. form.deptId = selected ? id : "";
  295. onSearch();
  296. }
  297. function openDialog(title = "新增", row?: FormItemProps) {
  298. addDialog({
  299. title: `${title}用户`,
  300. props: {
  301. formInline: {
  302. title,
  303. nickname: row?.nickname ?? "",
  304. username: row?.username ?? "",
  305. password: row?.password ?? "",
  306. roles: row?.roles ?? [],
  307. status: row?.status ?? 0,
  308. }
  309. },
  310. width: "40%",
  311. draggable: true,
  312. fullscreen: deviceDetection(),
  313. fullscreenIcon: true,
  314. closeOnClickModal: false,
  315. contentRenderer: () => h(editForm, { ref: formRef, formInline: null }),
  316. beforeSure: (done, { options }) => {
  317. const FormRef = formRef.value.getRef();
  318. const curData = options.props.formInline as FormItemProps;
  319. function chores() {
  320. message(`您${title}了用户名称为${curData.username}的这条数据`, {
  321. type: "success"
  322. });
  323. done(); // 关闭弹框
  324. onSearch(); // 刷新表格数据
  325. }
  326. FormRef.validate(valid => {
  327. if (valid) {
  328. console.log("curData", curData);
  329. // 表单规则校验通过
  330. if (title === "新增") {
  331. // 实际开发先调用新增接口,再进行下面操作
  332. if (curData.username == 'admin'
  333. || curData.username == 'root'
  334. || curData.username == 'eng') {
  335. message(`不能使用该用户名`, { type: "info" });
  336. return
  337. }
  338. addUser({ user: curData }).then((resp) => {
  339. if (resp.success) {
  340. chores();
  341. } else {
  342. message(`${title}用户名称为${curData.username}失败`, { type: "info" });
  343. }
  344. });
  345. } else {
  346. // 实际开发先调用修改接口,再进行下面操作
  347. modifyUser({ user: curData}).then((resp) => {
  348. if (resp.success) {
  349. chores();
  350. } else {
  351. message(`${title}用户名称为${curData.username}失败`, { type: "info" });
  352. }
  353. });
  354. }
  355. }
  356. });
  357. }
  358. });
  359. }
  360. watch(
  361. pwdForm,
  362. ({ newPwd }) =>
  363. (curScore.value = isAllEmpty(newPwd) ? -1 : zxcvbn(newPwd).score)
  364. );
  365. /** 重置密码 */
  366. function handleReset(row) {
  367. addDialog({
  368. title: `重置 ${row.username} 用户的密码`,
  369. width: "30%",
  370. draggable: true,
  371. closeOnClickModal: false,
  372. fullscreen: deviceDetection(),
  373. contentRenderer: () => (
  374. <>
  375. <ElForm ref={ruleFormRef} model={pwdForm}>
  376. <ElFormItem
  377. prop="newPwd"
  378. rules={[
  379. {
  380. required: true,
  381. message: "请输入新密码",
  382. trigger: "blur"
  383. }
  384. ]}
  385. >
  386. <ElInput
  387. clearable
  388. show-password
  389. type="password"
  390. v-model={pwdForm.newPwd}
  391. placeholder="请输入新密码"
  392. />
  393. </ElFormItem>
  394. </ElForm>
  395. <div class="my-4 flex">
  396. {pwdProgress.map(({ color, text }, idx) => (
  397. <div
  398. class="w-[19vw]"
  399. style={{ marginLeft: idx !== 0 ? "4px" : 0 }}
  400. >
  401. <ElProgress
  402. striped
  403. striped-flow
  404. duration={curScore.value === idx ? 6 : 0}
  405. percentage={curScore.value >= idx ? 100 : 0}
  406. color={color}
  407. stroke-width={10}
  408. show-text={false}
  409. />
  410. <p
  411. class="text-center"
  412. style={{ color: curScore.value === idx ? color : "" }}
  413. >
  414. {text}
  415. </p>
  416. </div>
  417. ))}
  418. </div>
  419. </>
  420. ),
  421. closeCallBack: () => (pwdForm.newPwd = ""),
  422. beforeSure: done => {
  423. ruleFormRef.value.validate(valid => {
  424. if (valid) {
  425. // 表单规则校验通过
  426. const user = row;
  427. user.password = pwdForm.newPwd;
  428. modifyUser({ user: user}).then((resp) => {
  429. if (resp.success) {
  430. message(`已成功重置 ${row.username} 用户的密码`, {
  431. type: "success"
  432. });
  433. console.log(pwdForm.newPwd);
  434. // 根据实际业务使用pwdForm.newPwd和row里的某些字段去调用重置用户密码接口即可
  435. done(); // 关闭弹框
  436. onSearch(); // 刷新表格数据
  437. } else {
  438. message(`重置 ${row.username} 用户的密码失败`, { type: "info" });
  439. }
  440. });
  441. }
  442. });
  443. }
  444. });
  445. }
  446. onMounted(async () => {
  447. onSearch();
  448. // 角色列表
  449. roleOptions.value = [];
  450. for (let i = 1; i < ROLES.length; i++) {
  451. roleOptions.value.push(ROLES[i]);
  452. }
  453. });
  454. return {
  455. form,
  456. loading,
  457. columns,
  458. dataList,
  459. selectedNum,
  460. pagination,
  461. buttonClass,
  462. deviceDetection,
  463. onSearch,
  464. resetForm,
  465. onbatchDel,
  466. openDialog,
  467. onTreeSelect,
  468. handleUpdate,
  469. handleDelete,
  470. handleReset,
  471. handleSizeChange,
  472. onSelectionCancel,
  473. handleCurrentChange,
  474. handleSelectionChange
  475. };
  476. }