index.vue 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <script setup lang="tsx">
  2. import { reactive, ref, unref } from 'vue'
  3. import { getWorker, addWorker, putWorker, delWorker } from '@/api/staff'
  4. import { useTable } from '@/hooks/web/useTable'
  5. import { useI18n } from '@/hooks/web/useI18n'
  6. import { Table, TableColumn } from '@/components/Table'
  7. import { Search } from '@/components/Search'
  8. import { FormSchema } from '@/components/Form'
  9. import { ContentWrap } from '@/components/ContentWrap'
  10. import Write from './components/Write.vue'
  11. import { BaseButton } from '@/components/Button'
  12. import { ElMessage, ElDivider, ElMessageBox, ElTag } from 'element-plus'
  13. import { Dialog } from '@/components/Dialog'
  14. import { TableImage } from '@/components/tableImage'
  15. import { designerData, designerSearch } from '@/api/staff/types'
  16. import { formatToDate } from '@/utils/dateUtil'
  17. const { t } = useI18n()
  18. const { tableRegister, tableState, tableMethods } = useTable({
  19. fetchDataApi: async () => {
  20. const { pageSize, currentPage } = tableState
  21. const res = await getWorker({
  22. page: unref(currentPage) || 1,
  23. limit: unref(pageSize) || 10,
  24. ...unref(searchParams)
  25. })
  26. return {
  27. list: res.data.list,
  28. total: res.data.count || 0
  29. }
  30. }
  31. })
  32. const { dataList, loading, total, currentPage, pageSize } = tableState
  33. const { getList } = tableMethods
  34. const tableColumns = reactive<TableColumn[]>([
  35. {
  36. field: 'id',
  37. label: 'ID',
  38. align: 'center',
  39. width: 70
  40. },
  41. {
  42. field: 'avatar',
  43. label: '头像',
  44. width: 80,
  45. slots: {
  46. default: ({ row }: any) => {
  47. return (
  48. <>
  49. <TableImage src={row.avatar} />
  50. </>
  51. )
  52. }
  53. }
  54. },
  55. {
  56. field: 'name',
  57. label: '姓名',
  58. minWidth: 100
  59. },
  60. {
  61. field: 'phone',
  62. label: '手机号',
  63. minWidth: 120
  64. },
  65. {
  66. field: 'start_job_year',
  67. label: '就业年份',
  68. align: 'center',
  69. headerAlign: 'center',
  70. minWidth: 100
  71. },
  72. {
  73. field: 'gender_chs',
  74. align: 'center',
  75. headerAlign: 'center',
  76. label: '性别',
  77. minWidth: 60
  78. },
  79. {
  80. field: 'area',
  81. label: '区域',
  82. minWidth: 200,
  83. slots: {
  84. default: ({ row }: any) => {
  85. return (
  86. <>
  87. {row.province_text} {row.city_text} {row.area_text}
  88. </>
  89. )
  90. }
  91. }
  92. },
  93. {
  94. field: 'detail_address',
  95. label: '定位',
  96. minWidth: 200
  97. },
  98. {
  99. field: 'tag_list_chs',
  100. label: '标签',
  101. minWidth: 100,
  102. slots: {
  103. default: ({ row }: any) => {
  104. return (
  105. <>
  106. {row.tag_list_chs.map((item: any) => {
  107. return (
  108. <>
  109. <ElTag type="primary">{item}</ElTag>
  110. </>
  111. )
  112. })}
  113. </>
  114. )
  115. }
  116. }
  117. },
  118. {
  119. field: 'action',
  120. label: t('userDemo.action'),
  121. width: 110,
  122. align: 'center',
  123. headerAlign: 'center',
  124. fixed: 'right',
  125. slots: {
  126. default: (data: any) => {
  127. const row = data.row
  128. return (
  129. <>
  130. <BaseButton link size="small" type="primary" onClick={() => action(row, 'edit')}>
  131. {t('exampleDemo.edit')}
  132. </BaseButton>
  133. <ElDivider direction="vertical" />
  134. <BaseButton link size="small" type="danger" onClick={() => delAction(row)}>
  135. {t('exampleDemo.del')}
  136. </BaseButton>
  137. </>
  138. )
  139. }
  140. }
  141. }
  142. ])
  143. const searchSchema = reactive<FormSchema[]>([
  144. {
  145. field: 'gender',
  146. label: '性别',
  147. component: 'Select',
  148. value: '',
  149. componentProps: {
  150. placeholder: '性别',
  151. options: [
  152. {
  153. label: '全部',
  154. value: ''
  155. },
  156. {
  157. label: '保密',
  158. value: 0
  159. },
  160. {
  161. label: '男',
  162. value: 1
  163. },
  164. {
  165. label: '女',
  166. value: 2
  167. }
  168. ]
  169. }
  170. },
  171. {
  172. field: 'tag_list',
  173. label: '标签',
  174. component: 'Input',
  175. value: '',
  176. componentProps: {
  177. placeholder: '请输入搜索标签'
  178. }
  179. },
  180. {
  181. field: 'name',
  182. label: '姓名',
  183. component: 'Input',
  184. value: '',
  185. componentProps: {
  186. placeholder: '请输入姓名'
  187. }
  188. }
  189. ])
  190. const searchParams = ref<designerSearch>({
  191. gender: '',
  192. tag_list: '',
  193. name: ''
  194. })
  195. const setSearchParams = (data: any) => {
  196. searchParams.value = data
  197. getList()
  198. }
  199. const dialogVisible = ref(false)
  200. const currentRow = ref()
  201. const dialogTitle = ref('')
  202. const actionType = ref('')
  203. const writeRef = ref<ComponentRef<typeof Write>>()
  204. const saveLoading = ref(false)
  205. const action = async (row: any, type: string) => {
  206. dialogTitle.value = t(type === 'edit' ? 'exampleDemo.edit' : 'exampleDemo.detail')
  207. actionType.value = type
  208. currentRow.value = {
  209. name: row.name,
  210. uid: row.uid,
  211. id: row.id,
  212. phone: row.phone,
  213. avatar: [row.avatar],
  214. gender: row.gender,
  215. birth_day_time: formatToDate(row.birth_day_time * 1000),
  216. province: row.province,
  217. city: row.city,
  218. area: row.area,
  219. tag_list: row.tag_list.split(','),
  220. longitude: row.longitude,
  221. latitude: row.latitude,
  222. detail_address: row.detail_address,
  223. start_job_year: row.start_job_year
  224. }
  225. dialogVisible.value = true
  226. }
  227. const AddAction = () => {
  228. dialogTitle.value = t('exampleDemo.add')
  229. currentRow.value = undefined
  230. dialogVisible.value = true
  231. actionType.value = ''
  232. }
  233. const save = async () => {
  234. const write = unref(writeRef)
  235. const formData = await write?.submit()
  236. if (formData) {
  237. saveLoading.value = true
  238. const data: designerData = {
  239. name: formData.name,
  240. uid: formData.uid,
  241. phone: formData.phone,
  242. avatar: formData.avatar[0],
  243. gender: formData.gender,
  244. birth_day_time: formatToDate(formData.birth_day_time),
  245. province: formData.province,
  246. city: formData.city,
  247. area: formData.area,
  248. tag_list: formData.tag_list,
  249. longitude: formData.longitude,
  250. latitude: formData.latitude,
  251. detail_address: formData.detail_address,
  252. start_job_year: formData.start_job_year
  253. }
  254. try {
  255. let res: any = {}
  256. if (actionType.value === 'edit') {
  257. data.id = formData.id
  258. res = await putWorker(data)
  259. } else if (actionType.value === '') {
  260. res = await addWorker(data)
  261. }
  262. if (res?.status === 200) {
  263. ElMessage({
  264. showClose: true,
  265. message: '保存成功',
  266. type: 'success'
  267. })
  268. getList()
  269. dialogVisible.value = false
  270. }
  271. } catch (error) {
  272. console.log(error)
  273. } finally {
  274. saveLoading.value = false
  275. }
  276. }
  277. }
  278. const delAction = (row: any) => {
  279. ElMessageBox.confirm('删除后无法恢复,是否删除?', {
  280. confirmButtonText: '删除',
  281. cancelButtonText: '取消',
  282. type: 'warning'
  283. })
  284. .then(async () => {
  285. const re = await delWorker(row.id)
  286. if (re) {
  287. ElMessage({
  288. showClose: true,
  289. message: '删除成功',
  290. type: 'success'
  291. })
  292. }
  293. await getList()
  294. })
  295. .catch(() => {})
  296. }
  297. </script>
  298. <template>
  299. <ContentWrap>
  300. <div class="searchBox">
  301. <Search :schema="searchSchema" @reset="setSearchParams" @search="setSearchParams" />
  302. </div>
  303. <div class="mb-10px">
  304. <BaseButton type="primary" @click="AddAction">{{ t('exampleDemo.add') }}</BaseButton>
  305. </div>
  306. <Table
  307. v-model:current-page="currentPage"
  308. v-model:page-size="pageSize"
  309. :columns="tableColumns"
  310. default-expand-all
  311. node-key="id"
  312. stripe
  313. :data="dataList"
  314. :loading="loading"
  315. @register="tableRegister"
  316. :pagination="{
  317. total
  318. }"
  319. />
  320. </ContentWrap>
  321. <Dialog v-model="dialogVisible" :title="dialogTitle" width="900px" max-height="700px">
  322. <Write v-if="actionType !== 'detail'" ref="writeRef" :current-row="currentRow" />
  323. <template #footer>
  324. <BaseButton
  325. v-if="actionType !== 'detail'"
  326. type="primary"
  327. :loading="saveLoading"
  328. @click="save"
  329. >
  330. {{ t('exampleDemo.save') }}
  331. </BaseButton>
  332. <BaseButton @click="dialogVisible = false">{{ t('dialogDemo.close') }}</BaseButton>
  333. </template>
  334. </Dialog>
  335. </template>
  336. <style lang="less">
  337. .searchBox {
  338. max-width: 1000px;
  339. }
  340. </style>