index.vue 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  1. <template>
  2. <div class="hc-layout-box">
  3. <div class="hc-layout-left-box">
  4. <div class="user-avatar-box">
  5. <div v-loading="avatarLoading" class="user-avatar">
  6. <img :src="userInfo.avatar || avatarPng" alt="">
  7. <div class="user-avatar-upload">
  8. <el-upload
  9. :accept="accept" :action="action" :before-upload="beforeUpload" :data="upData"
  10. :headers="getHeader()" :on-error="uploadError" :on-success="uploadFinish"
  11. :show-file-list="false" class="upload-dom"
  12. >
  13. <HcIcon fill name="camera" />
  14. </el-upload>
  15. </div>
  16. </div>
  17. <div class="user-name truncate">{{ userInfo.real_name || '游客' }}</div>
  18. </div>
  19. <div class="user-menu-box">
  20. <el-scrollbar>
  21. <HcMenuSimple :datas="menuOptions" :keys="menuKey" @change="handleMenuValue" />
  22. </el-scrollbar>
  23. </div>
  24. </div>
  25. <div class="hc-layout-content-box">
  26. <HcNewCard
  27. v-if="menuKey !== 'log' && menuKey !== 'recycle'" :title="menuItem.label" :ui="basicHight ? 'basic-hight' : ''"
  28. scrollbar
  29. >
  30. <template #extra>
  31. <span
  32. v-if="menuKey === 'basic' && !basicFormEdit" class="text-link"
  33. @click="basicFormEditClick"
  34. >编辑</span>
  35. <span
  36. v-if="menuKey === 'project'" class="text-link"
  37. @click="setDefaultProjectClick"
  38. >设置默认项目</span>
  39. </template>
  40. <template v-if="menuKey === 'basic'">
  41. <el-form
  42. ref="formUserRef" :model="formUserModel" :rules="formUserRules" label-position="top"
  43. size="large"
  44. >
  45. <el-row :gutter="20">
  46. <el-col :span="12">
  47. <el-form-item label="用户名称">
  48. <el-input v-model="formUserModel.real_name" disabled />
  49. </el-form-item>
  50. </el-col>
  51. <el-col :span="12">
  52. <el-form-item label="登录账号">
  53. <el-input v-model="formUserModel.account" disabled placeholder="" />
  54. </el-form-item>
  55. </el-col>
  56. <el-col :span="12">
  57. <el-form-item label="身份证号">
  58. <el-input v-model="formUserModel.idNumber" disabled placeholder="" />
  59. </el-form-item>
  60. </el-col>
  61. <el-col :span="12">
  62. <el-form-item :prop="basicFormEdit ? 'phone' : ''" label="绑定手机">
  63. <el-input
  64. v-model="formUserModel.phone" :disabled="!basicHight"
  65. placeholder="请输入绑定手机"
  66. />
  67. </el-form-item>
  68. </el-col>
  69. <el-col :span="12">
  70. <el-form-item label="所属角色">
  71. <el-input v-model="formUserModel.roleName" disabled placeholder="" />
  72. </el-form-item>
  73. </el-col>
  74. <el-col :span="12">
  75. <el-form-item label="所属部门">
  76. <el-input v-model="formUserModel.deptId" disabled placeholder="" />
  77. </el-form-item>
  78. </el-col>
  79. <el-col :span="12">
  80. <el-form-item label="CA签字体">
  81. <el-image
  82. v-if="formUserModel?.signatureUrl" :initial-index="0"
  83. :preview-src-list="[formUserModel?.signatureUrl]" :src="formUserModel?.signatureUrl"
  84. fit="cover" style="height: 60px"
  85. />
  86. <span v-else class="text-zinc-400">无CA签字体</span>
  87. </el-form-item>
  88. </el-col>
  89. </el-row>
  90. </el-form>
  91. </template>
  92. <template v-if="menuKey === 'password'">
  93. <el-form
  94. ref="formUserPassRef" :model="formUserPassModel" :rules="formUserPassRules" label-position="top"
  95. size="large" style="max-width: 400px; margin: auto;"
  96. >
  97. <el-form-item label="原始密码" prop="oldPassword">
  98. <el-input
  99. v-model="formUserPassModel.oldPassword" placeholder="请输入原始密码"
  100. show-password type="password"
  101. />
  102. </el-form-item>
  103. <el-form-item label="新的密码" prop="newPassword">
  104. <el-input
  105. v-model="formUserPassModel.newPassword" placeholder="请输入新的密码"
  106. show-password type="password"
  107. />
  108. </el-form-item>
  109. <el-form-item label="确认新密码" prop="newPassword1">
  110. <el-input
  111. v-model="formUserPassModel.newPassword1" placeholder="请输入确认新密码"
  112. show-password type="password"
  113. />
  114. </el-form-item>
  115. </el-form>
  116. </template>
  117. <template v-if="menuKey === 'project'">
  118. <el-menu :default-active="projectKey" class="hc-project-menu" unique-opened>
  119. <el-sub-menu v-for="item in projectContractArr" :index="item.id">
  120. <template #title>
  121. <HcIcon class="hc-menu-icon" name="folder-2" />
  122. <span>{{ item?.name }}</span>
  123. </template>
  124. <el-menu-item
  125. v-for="items in item?.contractInfoList ?? []" :index="items?.id"
  126. @click="projectMenuValue(item, items)"
  127. >
  128. <HcIcon v-if="projectKey === items?.id" class="hc-menu-icon" fill name="star" />
  129. <span>{{ items?.name }}</span>
  130. </el-menu-item>
  131. </el-sub-menu>
  132. </el-menu>
  133. </template>
  134. </HcNewCard>
  135. <div v-if="basicFormEdit" class="hc-card-foot-box">
  136. <el-button :loading="saveUserLoading" hc-btn type="primary" @click="saveUserInfoClick">
  137. <HcIcon name="save" />
  138. <span>保存</span>
  139. </el-button>
  140. <el-button hc-btn @click="cancelUserClick">
  141. <HcIcon name="close" />
  142. <span>取消</span>
  143. </el-button>
  144. </div>
  145. <HcNewCard v-if="menuKey === 'log'" :title="menuItem.label">
  146. <template #search>
  147. <div class="flex items-center">
  148. <div class="w-32">
  149. <el-select
  150. v-model="searchLogForm.operationModule" clearable placeholder="业务模块"
  151. @change="BusinessModuleValue"
  152. >
  153. <el-option
  154. v-for="item in operationModuleData" :key="item.value"
  155. :label="item?.dictValue" :value="item?.dictKey"
  156. />
  157. </el-select>
  158. </div>
  159. <div class="ml-2 w-32">
  160. <el-select
  161. v-model="searchLogForm.operationView" clearable placeholder="页面"
  162. @change="OperationViewValue"
  163. >
  164. <el-option
  165. v-for="item in operationViewData" :key="item.value" :label="item?.dictValue"
  166. :value="item?.dictKey"
  167. />
  168. </el-select>
  169. </div>
  170. <div class="ml-2 w-40">
  171. <el-select v-model="searchLogForm.operationType" clearable placeholder="操作类型">
  172. <el-option
  173. v-for="item in operationTypeData" :key="item.value" :label="item?.dictValue"
  174. :value="item?.dictKey"
  175. />
  176. </el-select>
  177. </div>
  178. <div class="ml-2 w-20">
  179. <el-select v-model="searchLogForm.operationMedium" clearable placeholder="设备">
  180. <el-option
  181. v-for="item in deviceData" :key="item.value" :label="item?.label"
  182. :value="item?.value"
  183. />
  184. </el-select>
  185. </div>
  186. <div class="ml-2 w-20">
  187. <el-select v-model="searchLogForm.createUser" clearable placeholder="操作人">
  188. <el-option
  189. v-for="item in userListData" :key="item.userId" :label="item?.userName"
  190. :value="item?.userId"
  191. />
  192. </el-select>
  193. </div>
  194. <div class="ml-2 w-64">
  195. <HcDatePicker :dates="betweenTime" clearable @change="betweenDateUpdate" />
  196. </div>
  197. <div class="ml-2 w-60">
  198. <el-input
  199. v-model="searchLogForm.queryValue" clearable placeholder="请输入名称关键词检索"
  200. @keyup="keyUpEvent"
  201. />
  202. </div>
  203. <div class="ml-2">
  204. <el-button type="primary" @click="searchClick">
  205. <HcIcon name="search-2" />
  206. <span>搜索</span>
  207. </el-button>
  208. </div>
  209. </div>
  210. </template>
  211. <HcTable :column="logTableColumn" :datas="logTableData" :loading="logTableLoading" is-new :index-style="{ width: 60 }">
  212. <template #operationContent="{ row }">
  213. <div class="text-link text-cut" @click="tableOperationContent(row)">
  214. {{ row?.operationContent }}
  215. </div>
  216. </template>
  217. </HcTable>
  218. <template #action>
  219. <HcPages :pages="searchLogForm" @change="pageLogChange" />
  220. </template>
  221. </HcNewCard>
  222. <HcNewCard v-if="menuKey === 'recycle'" action-size="lg">
  223. <template #header>
  224. <div class="mr-5">{{ menuItem.label }}</div>
  225. <HcNewSwitch :datas="userTypeTab" :keys="userTypeKey" size="default" @change="userTypeChange" />
  226. </template>
  227. <template #extra>
  228. <HcNewSwitch :datas="tabTypeTab" :keys="tabTypeKey" size="default" @change="tabTypeChange" />
  229. </template>
  230. <HcTable
  231. ref="recycleTableRef" :column="recycleTableColumn" :datas="recycleTableData" :loading="recycleTableLoading"
  232. is-new :index-style="{ width: 60 }" is-check :check-style="{ width: 29 }"
  233. @selection-change="recycleTableSelectionChange"
  234. >
  235. <template #fileName="{ row }">
  236. <div :class="{ 'text-red': row?.status === 2 }">
  237. {{ row?.fileName }}
  238. </div>
  239. </template>
  240. </HcTable>
  241. <template #action>
  242. <div class="foot-recycle">
  243. <el-button
  244. :loading="recycleBtnLoading" hc-btn type="primary"
  245. @click="recycleBtnClick"
  246. >
  247. <HcIcon fill name="reply" />
  248. <span>恢复</span>
  249. </el-button>
  250. <HcPages :pages="searchRecycleForm" @change="pageRecycleChange" />
  251. </div>
  252. </template>
  253. </HcNewCard>
  254. </div>
  255. <!-- 日志内容 -->
  256. <hc-new-dialog v-model="operationContentModal" title="日志内容" widths="38rem">
  257. <!-- {{ operationContent }} -->
  258. <div v-html="saveData" />
  259. </hc-new-dialog>
  260. </div>
  261. </template>
  262. <script setup>
  263. import { onMounted, ref } from 'vue'
  264. import { useAppStore } from '~src/store'
  265. import userApi from '~api/userInfo/index'
  266. import { useRoute, useRouter } from 'vue-router'
  267. import avatarPng from '~src/assets/images/avatar.png'
  268. import { getHeader } from 'hc-vue3-ui'
  269. import { arrIndex, formValidate, getArrValue, isPhone } from 'js-fast-way'
  270. import { getContractUserList } from '~api/other'
  271. import md5 from 'js-md5'
  272. //初始变量
  273. const router = useRouter()
  274. const useRoutes = useRoute()
  275. const useAppState = useAppStore()
  276. //全局变量信息
  277. const userInfo = ref(useAppState.getUserInfo)
  278. const projectId = ref(useAppState.getProjectId)
  279. const contractId = ref(useAppState.getContractId)
  280. const projectContractArr = ref(useAppState.getProjectContract)
  281. //路由参数数据
  282. const routerQuery = useRoutes?.query
  283. let MenuType = routerQuery?.MenuType || 'basic'
  284. //上传组件参数
  285. const action = '/api/blade-resource/oss/endpoint/put-file'
  286. const accept = 'image/png,image/jpg,image/jpeg'
  287. const upData = ref({})
  288. //上传前
  289. const avatarLoading = ref(false)
  290. const beforeUpload = () => {
  291. avatarLoading.value = true
  292. return true
  293. }
  294. //上传完成
  295. const uploadFinish = async (res) => {
  296. const link = res?.data?.link ?? ''
  297. const user_id = userInfo.value?.user_id ?? ''
  298. if (link) {
  299. const { error, code, msg } = await userApi.updateUserInfo({ avatar: link, id: user_id })
  300. if (!error && code === 200) {
  301. avatarLoading.value = false
  302. userInfo.value.avatar = link
  303. window?.$message?.success('更换头像成功')
  304. useAppState.setUserInfo(userInfo.value)
  305. } else {
  306. window?.$message?.error(msg || '操作失败')
  307. avatarLoading.value = false
  308. }
  309. } else {
  310. window?.$message?.warning('上传头像异常,请稍后再试')
  311. avatarLoading.value = false
  312. }
  313. }
  314. //上传失败
  315. const uploadError = () => {
  316. avatarLoading.value = false
  317. window?.$message?.warning('上传头像失败')
  318. }
  319. //左侧菜单
  320. const menuKey = ref(MenuType)
  321. const menuItem = ref({})
  322. const menuOptions = ref([
  323. { key: 'basic', label: '基础信息', icon: 'user-3' },
  324. { key: 'password', label: '密码设置', icon: 'lock-unlock' },
  325. { key: 'project', label: '参建项目', icon: 'folder-2' },
  326. { key: 'log', label: '操作日志', icon: 'file-mark' },
  327. { key: 'recycle', label: '回收站', icon: 'delete-bin-5' },
  328. ])
  329. //获取菜单对象数据
  330. const menuObjItem = () => {
  331. const index = arrIndex(menuOptions.value, 'key', menuKey.value)
  332. menuItem.value = menuOptions.value[index]
  333. }
  334. //菜单被点击
  335. const handleMenuValue = (item) => {
  336. menuItem.value = item
  337. menuKey.value = item?.key
  338. router.push({
  339. path: useRoutes.path,
  340. query: {
  341. MenuType: item?.key,
  342. },
  343. })
  344. getPageTypeData(item?.key)
  345. }
  346. //获取用户列表
  347. const userListData = ref([])
  348. const getUserListData = async () => {
  349. const { data } = await getContractUserList({
  350. contractId: contractId.value,
  351. })
  352. userListData.value = getArrValue(data)
  353. }
  354. //渲染完成
  355. onMounted(() => {
  356. menuObjItem()
  357. getPageTypeData(menuKey.value)
  358. getUserListData()
  359. })
  360. //根据类型,获取相关数据
  361. const getPageTypeData = (key) => {
  362. //编辑状态
  363. if (key === 'password') {
  364. basicFormEdit.value = true
  365. basicHight.value = true
  366. } else {
  367. basicFormEdit.value = false
  368. basicHight.value = false
  369. }
  370. //请求数据
  371. if (key === 'basic') {
  372. queryCurrentUserData()
  373. } else if (key === 'project') {
  374. getDefaultProject()
  375. } else if (key === 'log') {
  376. queryBusinessModule()
  377. queryOperationView()
  378. operationTypeStatus()
  379. getLogTableData()
  380. } else if (key === 'recycle') {
  381. getRecycleTableData()
  382. }
  383. }
  384. //是否编辑
  385. const basicFormEdit = ref(false)
  386. const basicHight = ref(false)
  387. //基础信息表单
  388. const formUserRef = ref(null)
  389. const formUserModel = ref(userInfo.value)
  390. const formUserRules = {
  391. phone: {
  392. required: true,
  393. validator: (rule, value, callback) => {
  394. if (!value) {
  395. callback(new Error('请输入手机号'))
  396. } else if (!isPhone(value)) {
  397. callback(new Error('手机号码格式错误'))
  398. } else {
  399. callback()
  400. }
  401. },
  402. trigger: 'blur',
  403. },
  404. }
  405. //获取用户信息
  406. const queryCurrentUserData = async () => {
  407. const { error, code, data } = await userApi.queryCurrentUserData()
  408. if (!error && code === 200) {
  409. formUserModel.value.deptId = data?.deptId || ''
  410. formUserModel.value.idNumber = data?.idNumber || ''
  411. formUserModel.value.roleName = data?.roleName || ''
  412. formUserModel.value.signatureUrl = data?.signatureUrl || ''
  413. }
  414. }
  415. //切换编辑模式
  416. const basicFormEditClick = () => {
  417. basicFormEdit.value = true
  418. basicHight.value = true
  419. }
  420. //保存数据
  421. const saveUserLoading = ref(false)
  422. const saveUserInfoClick = () => {
  423. const key = menuKey.value
  424. if (key === 'basic') {
  425. saveUserInfoData()
  426. } else if (key === 'password') {
  427. saveUpdatePassword()
  428. }
  429. }
  430. //取消修改
  431. const cancelUserClick = () => {
  432. const key = menuKey.value
  433. if (key === 'basic') {
  434. basicFormEdit.value = false
  435. basicHight.value = false
  436. } else {
  437. console.log('我也不知道这个点了干什么,反正UI图上有,至于有什么作用,不知道。。')
  438. }
  439. }
  440. //保存用户信息
  441. const saveUserInfoData = async () => {
  442. const { phone, user_id } = formUserModel.value
  443. if (phone && isPhone(phone)) {
  444. saveUserLoading.value = true
  445. const { error, code, msg } = await userApi.updateUserInfo({
  446. phone: phone,
  447. id: user_id,
  448. })
  449. if (!error && code === 200) {
  450. saveUserLoading.value = false
  451. window?.$message?.success('保存成功')
  452. userInfo.value.phone = phone
  453. useAppState.setUserInfo(userInfo.value)
  454. } else {
  455. window?.$message?.error(msg || '操作失败')
  456. saveUserLoading.value = false
  457. }
  458. }
  459. }
  460. //密码设置表单
  461. const formUserPassRef = ref(null)
  462. const formUserPassModel = ref({ oldPassword: '', newPassword: '', newPassword1: '' })
  463. const formUserPassRules = {
  464. oldPassword: {
  465. required: true,
  466. trigger: 'blur',
  467. message: '请输入原始密码',
  468. },
  469. newPassword: {
  470. required: true,
  471. validator(rule, value, callback) {
  472. const pass = formUserPassModel.value.newPassword1
  473. if (!value) {
  474. callback(new Error('请输入新的密码'))
  475. } else if (pass && value !== pass) {
  476. callback(new Error('新的密码和确认新密码不一致'))
  477. }
  478. callback()
  479. },
  480. trigger: 'blur',
  481. },
  482. newPassword1: {
  483. required: true,
  484. validator(rule, value, callback) {
  485. const pass = formUserPassModel.value.newPassword
  486. if (!value) {
  487. callback(new Error('请输入确认新密码'))
  488. } else if (pass && value !== pass) {
  489. callback(new Error('新的密码和确认新密码不一致'))
  490. }
  491. callback()
  492. },
  493. trigger: 'blur',
  494. },
  495. }
  496. //更新密码
  497. const saveUpdatePassword = async () => {
  498. const res = await formValidate(formUserPassRef.value)
  499. if (res) {
  500. const form = formUserPassModel.value
  501. saveUserLoading.value = true
  502. const { error, code, msg } = await userApi.updatePassword({
  503. oldPassword: md5(form?.oldPassword),
  504. newPassword: md5(form?.newPassword),
  505. newPassword1: md5(form?.newPassword1),
  506. plaintextPassword: form?.newPassword,
  507. })
  508. if (!error && code === 200) {
  509. saveUserLoading.value = false
  510. window?.$message?.success('密码修改成功')
  511. formUserPassModel.value = {
  512. oldPassword: '',
  513. newPassword: '',
  514. newPassword1: '',
  515. }
  516. } else {
  517. window?.$message?.error(msg || '操作失败')
  518. saveUserLoading.value = false
  519. }
  520. }
  521. }
  522. //获取默认项目
  523. const projectKey = ref(null)
  524. const getDefaultProject = async () => {
  525. const { error, code, data } = await userApi.getDefaultProject()
  526. if (!error && code === 200) {
  527. projectKey.value = data['contractId']
  528. }
  529. }
  530. //项目被选择
  531. const menuProjectId = ref('')
  532. const menuContractId = ref('')
  533. const projectMenuValue = (item, items) => {
  534. menuProjectId.value = item?.id
  535. menuContractId.value = items?.id
  536. projectKey.value = items?.id
  537. }
  538. //设置为默认项目
  539. const setDefaultProjectClick = async () => {
  540. const pid = menuProjectId.value, cid = menuContractId.value
  541. if (pid && cid) {
  542. const { error, code, msg } = await userApi.setDefaultProject({
  543. projectId: pid,
  544. contractId: cid,
  545. })
  546. if (!error && code === 200) {
  547. window?.$message?.success('设置成功')
  548. } else {
  549. window?.$message?.error(msg || '操作失败')
  550. }
  551. } else {
  552. window?.$message?.warning('请先在下方选择一个项目合同段')
  553. }
  554. }
  555. //搜索和分页数据
  556. const searchLogForm = ref({
  557. operationModule: null, operationView: null, operationType: null, operationMedium: null,
  558. queryValue: null, startTime: null, endTime: null,
  559. current: 1, size: 10, total: 0, createUser:null,
  560. })
  561. //业务模块
  562. const operationModuleData = ref([])
  563. const queryBusinessModule = async () => {
  564. const { error, code, data } = await userApi.queryBusinessModule()
  565. if (!error && code === 200) {
  566. operationModuleData.value = data
  567. } else {
  568. operationModuleData.value = []
  569. }
  570. }
  571. const BusinessModuleValue = () => {
  572. searchLogForm.value.operationView = null
  573. searchLogForm.value.operationType = null
  574. queryOperationView()
  575. operationTypeStatus()
  576. }
  577. //页面
  578. const operationViewData = ref([])
  579. const queryOperationView = async () => {
  580. const { error, code, data } = await userApi.queryOperationView({
  581. businessModule: searchLogForm.value?.operationModule || '',
  582. })
  583. if (!error && code === 200) {
  584. operationViewData.value = data
  585. } else {
  586. operationViewData.value = []
  587. }
  588. }
  589. const OperationViewValue = () => {
  590. searchLogForm.value.operationType = null
  591. operationTypeStatus()
  592. }
  593. //操作类型
  594. const operationTypeData = ref([])
  595. const operationTypeStatus = async () => {
  596. const { error, code, data } = await userApi.queryOperationTypeList({
  597. businessModule: searchLogForm.value?.operationModule || '',
  598. operationView: searchLogForm.value?.operationView || '',
  599. })
  600. if (!error && code === 200) {
  601. operationTypeData.value = data
  602. } else {
  603. operationTypeData.value = []
  604. }
  605. }
  606. //设备
  607. const deviceData = ref([{ label: 'APP', value: 'APP' }, { label: 'PC', value: 'PC' }])
  608. //表格数据
  609. const logTableColumn = ref([
  610. { key: 'operationModule', name: '业务模块', width: '180' },
  611. { key: 'operationTypeValue', name: '操作类型', width: '220' },
  612. { key: 'operationMedium', name: '设备', align: 'center', width: '80' },
  613. { key: 'operationContent', name: '操作内容' },
  614. { key: 'createUserName', name: '操作人', align: 'center', width: '120' },
  615. { key: 'createTime', name: '操作时间', align: 'center', width: '180' },
  616. ])
  617. const logTableData = ref([])
  618. //日期时间被选择
  619. const betweenTime = ref(null)
  620. const betweenDateUpdate = ({ val, arr }) => {
  621. betweenTime.value = arr
  622. searchLogForm.value.startTime = val?.start
  623. searchLogForm.value.endTime = val?.end
  624. }
  625. //回车搜索
  626. const keyUpEvent = (e) => {
  627. if (e.key === 'Enter') {
  628. searchLogForm.value.current = 1
  629. getLogTableData()
  630. }
  631. }
  632. //搜索
  633. const searchClick = () => {
  634. searchLogForm.value.current = 1
  635. getLogTableData()
  636. }
  637. //分页被点击
  638. const pageLogChange = ({ current, size }) => {
  639. searchLogForm.value.current = current
  640. searchLogForm.value.size = size
  641. getLogTableData()
  642. }
  643. //获取数据
  644. const logTableLoading = ref(false)
  645. const getLogTableData = async () => {
  646. logTableLoading.value = true
  647. const { error, code, data } = await userApi.getOperationLog({
  648. projectId: projectId.value,
  649. contractId: contractId.value,
  650. ...searchLogForm.value,
  651. })
  652. logTableLoading.value = false
  653. if (!error && code === 200) {
  654. logTableData.value = getArrValue(data['records'])
  655. searchLogForm.value.total = data.total || 0
  656. } else {
  657. logTableData.value = []
  658. searchLogForm.value.total = 0
  659. }
  660. }
  661. //查看日志内容
  662. const operationContentModal = ref(false)
  663. const operationContent = ref('')
  664. const saveData = ref('')
  665. const tableOperationContent = (row) => {
  666. operationContent.value = row['operationContent'] ?? ''
  667. saveData.value = row['saveData']
  668. operationContentModal.value = true
  669. }
  670. //个人和全部切换
  671. const userTypeKey = ref('1')
  672. const userTypeTab = ref([{ key: '1', name: '个人' }, { key: '2', name: '全部' }])
  673. const userTypeChange = (item) => {
  674. userTypeKey.value = item?.key
  675. if (item?.key === '1') {
  676. searchRecycleForm.value.createUserName = ''
  677. } else {
  678. searchRecycleForm.value.createUserName = 'ALL'
  679. }
  680. getRecycleTableData()
  681. }
  682. //结构类型tab数据和相关处理
  683. const tabTypeKey = ref('1')
  684. const tabTypeTab = ref([
  685. { key: '1', name: '文件资料' },
  686. { key: '2', name: '工程划分' },
  687. ])
  688. const tabTypeChange = (item) => {
  689. tabTypeKey.value = item?.key
  690. tabTypeKey.value = item?.key
  691. searchRecycleForm.value.current = 1
  692. searchRecycleForm.value.delType = item?.key
  693. getRecycleTableData()
  694. }
  695. //搜索和分页数据
  696. const searchRecycleForm = ref({
  697. projectId: projectId.value, contractId: contractId.value, createUserName: '',
  698. delType: tabTypeKey.value, current: 1, size: 20, total: 0,
  699. })
  700. //表格数据
  701. const recycleTableRef = ref(null)
  702. const recycleTableColumn = ref([
  703. { key: 'fileName', name: '删除内容' },
  704. { key: 'position', name: '父节点名称' },
  705. { key: 'createUserName', name: '操作人' },
  706. { key: 'operationTime', name: '删除时间', align: 'center', width: '180' },
  707. ])
  708. const recycleTableLoading = ref(false)
  709. const recycleTableData = ref(null)
  710. //分页被点击
  711. const pageRecycleChange = ({ current, size }) => {
  712. searchRecycleForm.value.current = current
  713. searchRecycleForm.value.size = size
  714. getRecycleTableData()
  715. }
  716. //获取数据
  717. const getRecycleTableData = async () => {
  718. const { error, code, data } = await userApi.queryRecycleBinList({
  719. projectId: projectId.value,
  720. contractId: contractId.value,
  721. delType: tabTypeKey.value,
  722. ...searchRecycleForm.value,
  723. })
  724. if (!error && code === 200) {
  725. recycleTableData.value = getArrValue(data['records'])
  726. searchRecycleForm.value.total = data.total || 0
  727. } else {
  728. recycleTableData.value = []
  729. searchRecycleForm.value.total = 0
  730. }
  731. }
  732. //多选
  733. const RecycleCheckedKeys = ref([])
  734. const recycleTableSelectionChange = (val) => {
  735. RecycleCheckedKeys.value = val
  736. }
  737. //恢复
  738. const recycleBtnLoading = ref(false)
  739. const recycleBtnClick = async () => {
  740. const rows = RecycleCheckedKeys.value
  741. let hasUnoperableData = false
  742. // 遍历每一行数据,检查 status 字段
  743. for (const row of rows) {
  744. if (row.status === 2) {
  745. hasUnoperableData = true
  746. break
  747. }
  748. }
  749. // 如果存在 status = 2 的数据,则提示用户并返回
  750. if (hasUnoperableData) {
  751. window.$message.warning('存在不可操作的数据,请检查后再操作。')
  752. return
  753. }
  754. if (rows.length > 0) {
  755. //请求数据
  756. recycleBtnLoading.value = true
  757. const { error, code, msg } = await userApi.recycleBinRegain({
  758. projectId: projectId.value,
  759. contractId: contractId.value,
  760. delType: tabTypeKey.value,
  761. regainIds: rows,
  762. })
  763. recycleBtnLoading.value = false
  764. if (!error && code === 200) {
  765. window?.$message?.success('操作成功')
  766. searchRecycleForm.value.current = 1
  767. getRecycleTableData()
  768. } else {
  769. window?.$message?.error(msg || '操作失败')
  770. }
  771. } else {
  772. window.$message?.warning('请先勾选要恢复的数据')
  773. }
  774. }
  775. </script>
  776. <style lang="scss" scoped>
  777. @import "../../styles/user/index.scss";
  778. </style>
  779. <style lang="scss">
  780. .user-avatar-upload .upload-dom, .upload-dom .el-upload {
  781. height: 100%;
  782. width: 100%;
  783. }
  784. </style>