index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. <!-- vue 页面模板 -->
  2. <template>
  3. <div class="user">
  4. <Space wrap style="margin-bottom: 1em">
  5. <Button type="primary" icon="ios-search" @click="() => show_edit()">
  6. 新增
  7. </Button>
  8. <Input
  9. v-model="searchText"
  10. placeholder="请输入搜索内容"
  11. icon="ios-search"
  12. @on-click="() => change(1)"
  13. @on-enter="() => change(1)"
  14. >
  15. </Input>
  16. </Space>
  17. <Table highlight-row ref="currentRowTable" :columns="columns" :data="list">
  18. <template #tool="{ row }">
  19. <Space wrap>
  20. <Poptip
  21. transfer
  22. confirm
  23. width="90"
  24. title="删除该用户?"
  25. @on-ok="() => del_user(row)"
  26. >
  27. <Button size="small" type="error"> 删 除 </Button>
  28. </Poptip>
  29. <Button size="small" type="primary" @click="() => show_edit(row)">
  30. 修 改
  31. </Button>
  32. </Space>
  33. </template>
  34. <template #photo="{ row }">
  35. <Image :src="row.photo" fit="cover" width="58px" height="58px">
  36. <template #error>
  37. <Icon type="ios-image-outline" size="24" color="#ccc" />
  38. </template>
  39. </Image>
  40. </template>
  41. </Table>
  42. <br />
  43. <Page
  44. :total="total"
  45. show-sizer
  46. v-model="page"
  47. @on-change="change"
  48. @on-page-size-change="sizeChange"
  49. />
  50. <Drawer
  51. :mask-closable="false"
  52. title="用户详情"
  53. placement="right"
  54. v-model="show_user_edit"
  55. >
  56. <Form
  57. ref="formInline"
  58. :model="user"
  59. :rules="ruleInline"
  60. :label-width="80"
  61. >
  62. <FormItem label="用户名">
  63. <Input v-model="user.name" placeholder="请输入用户名"></Input>
  64. </FormItem>
  65. <FormItem label="头像">
  66. <div class="img-box" v-if="user.photo && user.photo.url">
  67. <Image
  68. :src="user.photo.url"
  69. fit="cover"
  70. width="100%"
  71. height="100%"
  72. />
  73. <Icon
  74. type="ios-trash-outline"
  75. class="check-icon"
  76. size="25"
  77. @click="handleRemove"
  78. ></Icon>
  79. </div>
  80. <Upload
  81. ref="upload"
  82. v-else
  83. :show-upload-list="false"
  84. :on-success="handle_success"
  85. :format="['jpg', 'jpeg', 'png']"
  86. :max-size="5120"
  87. :on-format-error="handle_format_error"
  88. :headers="{
  89. Authorization: token,
  90. }"
  91. type="drag"
  92. :action="base_url + '/admin/leaders/upload'"
  93. style="display: inline-block; width: 58px"
  94. >
  95. <div style="width: 58px; height: 58px; line-height: 58px">
  96. <Icon type="ios-camera" size="20"></Icon>
  97. </div>
  98. </Upload>
  99. </FormItem>
  100. <FormItem label="角色">
  101. <Select
  102. v-model="user.roleId"
  103. filterable
  104. :remote-method="get_role_data"
  105. :loading="isLoad"
  106. >
  107. <Option
  108. v-for="(option, index) in rules"
  109. :value="option.roleId"
  110. :key="index"
  111. >
  112. {{ option.name }}
  113. </Option>
  114. </Select>
  115. </FormItem>
  116. <FormItem label="机构">
  117. <Select
  118. v-model="user.organId"
  119. filterable
  120. :remote-method="get_regan_data"
  121. :loading="isLoad"
  122. >
  123. <Option
  124. v-for="(option, index) in organ"
  125. :value="option.organId"
  126. :key="index"
  127. >
  128. {{ option.name }}
  129. </Option>
  130. </Select>
  131. </FormItem>
  132. <FormItem label="地域">
  133. <TreeSelect v-model="user.regionId" :data="region" />
  134. </FormItem>
  135. <FormItem label="手机号">
  136. <Input v-model="user.phone" placeholder="请输入手机号"></Input>
  137. </FormItem>
  138. <FormItem label="密码">
  139. <Input
  140. v-model="user.newpassword"
  141. type="password"
  142. placeholder="请输入密码"
  143. ></Input>
  144. </FormItem>
  145. <FormItem label="简介">
  146. <Input
  147. v-model="user.info"
  148. type="textarea"
  149. :rows="4"
  150. placeholder="请输入简介"
  151. ></Input>
  152. </FormItem>
  153. <FormItem label="职位">
  154. <Input v-model="user.position" placeholder="请输入职位"></Input>
  155. </FormItem>
  156. <FormItem label="职级">
  157. <Input v-model="user.level" placeholder="请输入职级"></Input>
  158. </FormItem>
  159. <FormItem label="履历">
  160. <Input
  161. v-model="user.resume"
  162. type="textarea"
  163. :rows="4"
  164. placeholder="请输入履历"
  165. ></Input>
  166. </FormItem>
  167. <FormItem>
  168. <Button type="primary" @click="save_user">保 存</Button>
  169. </FormItem>
  170. </Form>
  171. </Drawer>
  172. </div>
  173. </template>
  174. <script setup>
  175. import { ref, onMounted } from 'vue';
  176. import { Image, Message } from 'view-ui-plus';
  177. import api from '../../api/index.js';
  178. import { base_url } from '../../config/index';
  179. const token = localStorage.getItem('neican_token');
  180. const searchText = ref('');
  181. const total = ref(0);
  182. const page = ref(1);
  183. const pageSize = ref(10);
  184. const formInline = ref(null);
  185. const upload = ref(null);
  186. const list = ref([]);
  187. const user = ref({
  188. headSculpture: [],
  189. photo: {},
  190. regionId: '',
  191. });
  192. const rules = ref([]);
  193. const organ = ref([]);
  194. const region = ref([]);
  195. const show_user_edit = ref(false);
  196. const isLoad = ref(false);
  197. const columns = [
  198. {
  199. title: '名字',
  200. key: 'name',
  201. align: 'center',
  202. },
  203. {
  204. title: '头像',
  205. slot: 'photo',
  206. align: 'center',
  207. },
  208. {
  209. title: '手机号',
  210. key: 'phone',
  211. align: 'center',
  212. },
  213. {
  214. title: '级别',
  215. key: 'level',
  216. align: 'center',
  217. },
  218. {
  219. title: '操作',
  220. slot: 'tool',
  221. align: 'center',
  222. },
  223. ];
  224. const ruleInline = {
  225. name: [
  226. {
  227. required: true,
  228. message: '请输入姓名',
  229. trigger: 'blur',
  230. },
  231. ],
  232. newpassword: [
  233. {
  234. required: true,
  235. message: '请输入密码',
  236. trigger: 'blur',
  237. },
  238. ],
  239. phone: [
  240. {
  241. required: true,
  242. message: '请输入手机号',
  243. trigger: 'blur',
  244. },
  245. ],
  246. };
  247. onMounted(() => {});
  248. get_list();
  249. get_role_data();
  250. get_regan_data();
  251. get_region_api();
  252. function change(p) {
  253. page.value = p;
  254. get_list();
  255. }
  256. function sizeChange(pageSize) {
  257. pageSize.value = pageSize;
  258. get_list();
  259. }
  260. function get_list() {
  261. api
  262. .custom_list_api({
  263. page: page.value,
  264. pageSize: pageSize.value,
  265. name: searchText.value,
  266. })
  267. .then(r => {
  268. list.value = r.records || [];
  269. total.value = r.total || 0;
  270. });
  271. }
  272. function show_edit(data) {
  273. const row = JSON.parse(JSON.stringify(data || {}));
  274. show_user_edit.value = true;
  275. if (row.photo)
  276. row.photo = {
  277. url: row.photo,
  278. };
  279. user.value = row || {
  280. headSculpture: [],
  281. photo: {},
  282. regionId: '',
  283. };
  284. }
  285. function save_user() {
  286. formInline.value.validate(valid => {
  287. if (!valid) return;
  288. const U = user.value;
  289. if (!U.userId)
  290. api
  291. .custom_add({
  292. name: U.name,
  293. regionId: U.regionId,
  294. organId: U.organId,
  295. phone: U.phone,
  296. password: U.newpassword,
  297. info: U.info,
  298. photo: U.photo.url,
  299. position: U.position,
  300. resume: U.resume,
  301. level: U.level,
  302. roleId: U.roleId,
  303. })
  304. .then(() => {
  305. Message.info('新增成功');
  306. show_user_edit.value = false;
  307. get_list();
  308. });
  309. else
  310. api
  311. .custom_updata({
  312. name: U.name,
  313. regionId: U.regionId,
  314. organId: U.organId,
  315. phone: U.phone,
  316. password: U.newpassword,
  317. info: U.info,
  318. photo: U.photo.url,
  319. position: U.position,
  320. resume: U.resume,
  321. level: U.level,
  322. roleId: U.roleId,
  323. userId: U.userId,
  324. })
  325. .then(() => {
  326. Message.info('修改成功');
  327. show_user_edit.value = false;
  328. get_list();
  329. });
  330. });
  331. }
  332. function get_role_data(query) {
  333. isLoad.value = true;
  334. api
  335. .user_role_api({
  336. page: 1,
  337. pageSize: 100000,
  338. name: query,
  339. })
  340. .then(r => {
  341. isLoad.value = false;
  342. rules.value = r.records || [];
  343. })
  344. .catch(err => {
  345. isLoad.value = false;
  346. });
  347. }
  348. function get_regan_data(query) {
  349. api
  350. .organ_api({
  351. page: 1,
  352. pageSize: 100000,
  353. name: query,
  354. })
  355. .then(r => {
  356. organ.value = r.records || [];
  357. });
  358. }
  359. function get_region_api() {
  360. api.region_api().then(r => {
  361. region.value = tree_change(r || []);
  362. });
  363. }
  364. function tree_change(list) {
  365. const li = [];
  366. for (let i = 0; i < list.length; i++) {
  367. const v = list[i];
  368. v.title = v.name;
  369. v.value = v.regionId;
  370. v.expand = false;
  371. v.selected = false;
  372. v.checked = false;
  373. li.children = tree_change(v.children || []);
  374. li.push(v);
  375. }
  376. return li;
  377. }
  378. function handle_success(response, file, fileList) {
  379. user.value.photo.url = response.data.url || '';
  380. user.value.photo.file = file || null;
  381. Message.info('头像上传成功');
  382. }
  383. function handle_format_error(file) {
  384. Message.info('头像上传失败');
  385. }
  386. function handleRemove() {
  387. user.value.photo.url = '';
  388. user.value.photo.file = null;
  389. }
  390. function del_user(row) {
  391. api.custom_del(row.userId).then(() => {
  392. Message.info('删除成功');
  393. get_list();
  394. });
  395. }
  396. </script>
  397. <style lang="scss">
  398. .img-box {
  399. width: 58px;
  400. height: 58px;
  401. position: relative;
  402. .check-icon {
  403. opacity: 0;
  404. transition: all 0.5s;
  405. position: absolute;
  406. top: 50%;
  407. left: 50%;
  408. transform: translate(-50%, -50%);
  409. z-index: 1;
  410. &:hover {
  411. opacity: 1;
  412. }
  413. }
  414. }
  415. </style>