index.vue 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  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. <template #search>
  231. <div class="w-250px">
  232. <hc-date-picker :dates="tabBetweenTime" clearable @change="tabBetweenTimeUpdate" />
  233. </div>
  234. <div class="ml-2 w-200px">
  235. <el-select v-model="searchRecleForm.userId" placeholder="操作人" filterable block>
  236. <el-option v-for="item in userData" :key="item.id" :label="item.contractName" :value="item.id" />
  237. </el-select>
  238. </div>
  239. <div class="ml-2 w-40">
  240. <el-select v-model="searchRecleForm.dataStatus" placeholder="是否资料节点" filterable clearable block>
  241. <el-option label="是" :value="1" />
  242. <el-option label="未引用" :value="0" />
  243. </el-select>
  244. </div>
  245. <div class="ml-2 w-72">
  246. <el-input v-model="searchRecleForm.queryValue" clearable placeholder="请输入工程划分" @keyup="keyUpEvent" />
  247. </div>
  248. <div class="ml-2">
  249. <el-button type="primary" @click="searchRecleClick">
  250. <hc-icon name="search-2" />
  251. <span>搜索</span>
  252. </el-button>
  253. </div>
  254. <div v-if="tabTypeKey === '1'" class="position-absolute right-0">
  255. <el-button type="success" :disabled="RecycleCheckedKeys.length < 1" @click="recoverClick">
  256. <hc-icon name="arrow-go-back" />
  257. <span>恢复</span>
  258. </el-button>
  259. </div>
  260. </template>
  261. <HcTable
  262. ref="recycleTableRef" :column="recycleTableColumn" :datas="recycleTableData" :loading="recycleTableLoading"
  263. is-new :index-style="{ width: 60 }" is-check :check-style="{ width: 29 }"
  264. @selection-change="recycleTableSelectionChange"
  265. >
  266. <template #fileName="{ row }">
  267. <div :class="{ 'text-red': row?.status === 2 }">
  268. {{ row?.fileName }}
  269. </div>
  270. </template>
  271. <template #action="{ row }">
  272. <el-link type="success" @click="recoverClick(row)">恢复</el-link>
  273. </template>
  274. </HcTable>
  275. <template #action>
  276. <div class="foot-recycle">
  277. <el-button
  278. :loading="recycleBtnLoading" hc-btn type="primary"
  279. :disabled="userTypeKey === '2'"
  280. @click="recycleBtnClick"
  281. >
  282. <HcIcon fill name="reply" />
  283. <span>恢复</span>
  284. </el-button>
  285. <HcPages :pages="searchRecycleForm" @change="pageRecycleChange" />
  286. </div>
  287. </template>
  288. </HcNewCard>
  289. </div>
  290. <!-- 日志内容 -->
  291. <hc-new-dialog v-model="operationContentModal" title="日志内容" widths="38rem">
  292. <!-- {{ operationContent }} -->
  293. <div v-html="saveData" />
  294. </hc-new-dialog>
  295. <!-- 恢复提醒 -->
  296. <hc-new-dialog v-model="recoverModal" title="恢复提醒">
  297. <div class="felx-col flex items-center justify-start font-bold">
  298. <div class="mr-4 text-24px">
  299. <HcIcon name="error-warning" class="text-orange" />
  300. </div>
  301. <div>
  302. <p class="mb-2">
  303. <span v-for="(item, index) in cheVal" :key="item.id" class="mb-2">
  304. {{ index === cheVal.length - 1 ? item.fileName : `${item.fileName}、` }}
  305. </span>
  306. 存在多条删除信息
  307. </p>
  308. <p> 是否恢复“删除位置”下所有的节点或文件</p>
  309. </div>
  310. </div>
  311. <p class="mt-2 text-orange"> * 可以通过搜索栏查询“删除位置”下包含哪些节点,请确认后谨慎选择</p>
  312. </hc-new-dialog>
  313. </div>
  314. </template>
  315. <script setup>
  316. import { onMounted, ref } from 'vue'
  317. import { useAppStore } from '~src/store'
  318. import userApi from '~api/userInfo/index'
  319. import { useRoute, useRouter } from 'vue-router'
  320. import avatarPng from '~src/assets/images/avatar.png'
  321. import { getHeader } from 'hc-vue3-ui'
  322. import { arrIndex, formValidate, getArrValue, isPhone } from 'js-fast-way'
  323. import { getContractUserList } from '~api/other'
  324. import md5 from 'js-md5'
  325. //初始变量
  326. const router = useRouter()
  327. const useRoutes = useRoute()
  328. const useAppState = useAppStore()
  329. //全局变量信息
  330. const userInfo = ref(useAppState.getUserInfo)
  331. const projectId = ref(useAppState.getProjectId)
  332. const contractId = ref(useAppState.getContractId)
  333. const projectContractArr = ref(useAppState.getProjectContract)
  334. //路由参数数据
  335. const routerQuery = useRoutes?.query
  336. let MenuType = routerQuery?.MenuType || 'basic'
  337. //上传组件参数
  338. const action = '/api/blade-resource/oss/endpoint/put-file'
  339. const accept = 'image/png,image/jpg,image/jpeg'
  340. const upData = ref({})
  341. //上传前
  342. const avatarLoading = ref(false)
  343. const beforeUpload = () => {
  344. avatarLoading.value = true
  345. return true
  346. }
  347. //上传完成
  348. const uploadFinish = async (res) => {
  349. const link = res?.data?.link ?? ''
  350. const user_id = userInfo.value?.user_id ?? ''
  351. if (link) {
  352. const { error, code, msg } = await userApi.updateUserInfo({ avatar: link, id: user_id })
  353. if (!error && code === 200) {
  354. avatarLoading.value = false
  355. userInfo.value.avatar = link
  356. window?.$message?.success('更换头像成功')
  357. useAppState.setUserInfo(userInfo.value)
  358. } else {
  359. window?.$message?.error(msg || '操作失败')
  360. avatarLoading.value = false
  361. }
  362. } else {
  363. window?.$message?.warning('上传头像异常,请稍后再试')
  364. avatarLoading.value = false
  365. }
  366. }
  367. //上传失败
  368. const uploadError = () => {
  369. avatarLoading.value = false
  370. window?.$message?.warning('上传头像失败')
  371. }
  372. //左侧菜单
  373. const menuKey = ref(MenuType)
  374. const menuItem = ref({})
  375. const menuOptions = ref([
  376. { key: 'basic', label: '基础信息', icon: 'user-3' },
  377. { key: 'password', label: '密码设置', icon: 'lock-unlock' },
  378. { key: 'project', label: '参建项目', icon: 'folder-2' },
  379. { key: 'log', label: '操作日志', icon: 'file-mark' },
  380. { key: 'recycle', label: '回收站', icon: 'delete-bin-5' },
  381. ])
  382. //获取菜单对象数据
  383. const menuObjItem = () => {
  384. const index = arrIndex(menuOptions.value, 'key', menuKey.value)
  385. menuItem.value = menuOptions.value[index]
  386. }
  387. //菜单被点击
  388. const handleMenuValue = (item) => {
  389. menuItem.value = item
  390. menuKey.value = item?.key
  391. router.push({
  392. path: useRoutes.path,
  393. query: {
  394. MenuType: item?.key,
  395. },
  396. })
  397. getPageTypeData(item?.key)
  398. }
  399. //获取用户列表
  400. const userListData = ref([])
  401. const getUserListData = async () => {
  402. const { data } = await getContractUserList({
  403. contractId: contractId.value,
  404. })
  405. userListData.value = getArrValue(data)
  406. }
  407. //渲染完成
  408. onMounted(() => {
  409. menuObjItem()
  410. getPageTypeData(menuKey.value)
  411. getUserListData()
  412. })
  413. //根据类型,获取相关数据
  414. const getPageTypeData = (key) => {
  415. //编辑状态
  416. if (key === 'password') {
  417. basicFormEdit.value = true
  418. basicHight.value = true
  419. } else {
  420. basicFormEdit.value = false
  421. basicHight.value = false
  422. }
  423. //请求数据
  424. if (key === 'basic') {
  425. queryCurrentUserData()
  426. } else if (key === 'project') {
  427. getDefaultProject()
  428. } else if (key === 'log') {
  429. queryBusinessModule()
  430. queryOperationView()
  431. operationTypeStatus()
  432. getLogTableData()
  433. } else if (key === 'recycle') {
  434. getRecycleTableData()
  435. }
  436. }
  437. //是否编辑
  438. const basicFormEdit = ref(false)
  439. const basicHight = ref(false)
  440. //基础信息表单
  441. const formUserRef = ref(null)
  442. const formUserModel = ref(userInfo.value)
  443. const formUserRules = {
  444. phone: {
  445. required: true,
  446. validator: (rule, value, callback) => {
  447. if (!value) {
  448. callback(new Error('请输入手机号'))
  449. } else if (!isPhone(value)) {
  450. callback(new Error('手机号码格式错误'))
  451. } else {
  452. callback()
  453. }
  454. },
  455. trigger: 'blur',
  456. },
  457. }
  458. //获取用户信息
  459. const queryCurrentUserData = async () => {
  460. const { error, code, data } = await userApi.queryCurrentUserData()
  461. if (!error && code === 200) {
  462. formUserModel.value.deptId = data?.deptId || ''
  463. formUserModel.value.idNumber = data?.idNumber || ''
  464. formUserModel.value.roleName = data?.roleName || ''
  465. formUserModel.value.signatureUrl = data?.signatureUrl || ''
  466. }
  467. }
  468. //切换编辑模式
  469. const basicFormEditClick = () => {
  470. basicFormEdit.value = true
  471. basicHight.value = true
  472. }
  473. //保存数据
  474. const saveUserLoading = ref(false)
  475. const saveUserInfoClick = () => {
  476. const key = menuKey.value
  477. if (key === 'basic') {
  478. saveUserInfoData()
  479. } else if (key === 'password') {
  480. saveUpdatePassword()
  481. }
  482. }
  483. //取消修改
  484. const cancelUserClick = () => {
  485. const key = menuKey.value
  486. if (key === 'basic') {
  487. basicFormEdit.value = false
  488. basicHight.value = false
  489. } else {
  490. console.log('我也不知道这个点了干什么,反正UI图上有,至于有什么作用,不知道。。')
  491. }
  492. }
  493. //保存用户信息
  494. const saveUserInfoData = async () => {
  495. const { phone, user_id } = formUserModel.value
  496. if (phone && isPhone(phone)) {
  497. saveUserLoading.value = true
  498. const { error, code, msg } = await userApi.updateUserInfo({
  499. phone: phone,
  500. id: user_id,
  501. })
  502. if (!error && code === 200) {
  503. saveUserLoading.value = false
  504. window?.$message?.success('保存成功')
  505. userInfo.value.phone = phone
  506. useAppState.setUserInfo(userInfo.value)
  507. } else {
  508. window?.$message?.error(msg || '操作失败')
  509. saveUserLoading.value = false
  510. }
  511. }
  512. }
  513. //密码设置表单
  514. const formUserPassRef = ref(null)
  515. const formUserPassModel = ref({ oldPassword: '', newPassword: '', newPassword1: '' })
  516. const formUserPassRules = {
  517. oldPassword: {
  518. required: true,
  519. trigger: 'blur',
  520. message: '请输入原始密码',
  521. },
  522. newPassword: {
  523. required: true,
  524. validator(rule, value, callback) {
  525. const pass = formUserPassModel.value.newPassword1
  526. if (!value) {
  527. callback(new Error('请输入新的密码'))
  528. } else if (pass && value !== pass) {
  529. callback(new Error('新的密码和确认新密码不一致'))
  530. }
  531. callback()
  532. },
  533. trigger: 'blur',
  534. },
  535. newPassword1: {
  536. required: true,
  537. validator(rule, value, callback) {
  538. const pass = formUserPassModel.value.newPassword
  539. if (!value) {
  540. callback(new Error('请输入确认新密码'))
  541. } else if (pass && value !== pass) {
  542. callback(new Error('新的密码和确认新密码不一致'))
  543. }
  544. callback()
  545. },
  546. trigger: 'blur',
  547. },
  548. }
  549. //更新密码
  550. const saveUpdatePassword = async () => {
  551. const res = await formValidate(formUserPassRef.value)
  552. if (res) {
  553. const form = formUserPassModel.value
  554. saveUserLoading.value = true
  555. const { error, code, msg } = await userApi.updatePassword({
  556. oldPassword: md5(form?.oldPassword),
  557. newPassword: md5(form?.newPassword),
  558. newPassword1: md5(form?.newPassword1),
  559. plaintextPassword: form?.newPassword,
  560. })
  561. if (!error && code === 200) {
  562. saveUserLoading.value = false
  563. window?.$message?.success('密码修改成功')
  564. formUserPassModel.value = {
  565. oldPassword: '',
  566. newPassword: '',
  567. newPassword1: '',
  568. }
  569. } else {
  570. window?.$message?.error(msg || '操作失败')
  571. saveUserLoading.value = false
  572. }
  573. }
  574. }
  575. //获取默认项目
  576. const projectKey = ref(null)
  577. const getDefaultProject = async () => {
  578. const { error, code, data } = await userApi.getDefaultProject()
  579. if (!error && code === 200) {
  580. projectKey.value = data['contractId']
  581. }
  582. }
  583. //项目被选择
  584. const menuProjectId = ref('')
  585. const menuContractId = ref('')
  586. const projectMenuValue = (item, items) => {
  587. menuProjectId.value = item?.id
  588. menuContractId.value = items?.id
  589. projectKey.value = items?.id
  590. }
  591. //设置为默认项目
  592. const setDefaultProjectClick = async () => {
  593. const pid = menuProjectId.value, cid = menuContractId.value
  594. if (pid && cid) {
  595. const { error, code, msg } = await userApi.setDefaultProject({
  596. projectId: pid,
  597. contractId: cid,
  598. })
  599. if (!error && code === 200) {
  600. window?.$message?.success('设置成功')
  601. } else {
  602. window?.$message?.error(msg || '操作失败')
  603. }
  604. } else {
  605. window?.$message?.warning('请先在下方选择一个项目合同段')
  606. }
  607. }
  608. //搜索和分页数据
  609. const searchLogForm = ref({
  610. operationModule: null, operationView: null, operationType: null, operationMedium: null,
  611. queryValue: null, startTime: null, endTime: null,
  612. current: 1, size: 10, total: 0, createUser:null,
  613. })
  614. //业务模块
  615. const operationModuleData = ref([])
  616. const queryBusinessModule = async () => {
  617. const { error, code, data } = await userApi.queryBusinessModule()
  618. if (!error && code === 200) {
  619. operationModuleData.value = data
  620. } else {
  621. operationModuleData.value = []
  622. }
  623. }
  624. const BusinessModuleValue = () => {
  625. searchLogForm.value.operationView = null
  626. searchLogForm.value.operationType = null
  627. queryOperationView()
  628. operationTypeStatus()
  629. }
  630. //页面
  631. const operationViewData = ref([])
  632. const queryOperationView = async () => {
  633. const { error, code, data } = await userApi.queryOperationView({
  634. businessModule: searchLogForm.value?.operationModule || '',
  635. })
  636. if (!error && code === 200) {
  637. operationViewData.value = data
  638. } else {
  639. operationViewData.value = []
  640. }
  641. }
  642. const OperationViewValue = () => {
  643. searchLogForm.value.operationType = null
  644. operationTypeStatus()
  645. }
  646. //操作类型
  647. const operationTypeData = ref([])
  648. const operationTypeStatus = async () => {
  649. const { error, code, data } = await userApi.queryOperationTypeList({
  650. businessModule: searchLogForm.value?.operationModule || '',
  651. operationView: searchLogForm.value?.operationView || '',
  652. })
  653. if (!error && code === 200) {
  654. operationTypeData.value = data
  655. } else {
  656. operationTypeData.value = []
  657. }
  658. }
  659. //设备
  660. const deviceData = ref([{ label: 'APP', value: 'APP' }, { label: 'PC', value: 'PC' }])
  661. //表格数据
  662. const logTableColumn = ref([
  663. { key: 'operationModule', name: '业务模块', width: '180' },
  664. { key: 'operationTypeValue', name: '操作类型', width: '220' },
  665. { key: 'operationMedium', name: '设备', align: 'center', width: '80' },
  666. { key: 'operationContent', name: '操作内容' },
  667. { key: 'createUserName', name: '操作人', align: 'center', width: '120' },
  668. { key: 'createTime', name: '操作时间', align: 'center', width: '180' },
  669. ])
  670. const logTableData = ref([])
  671. //日期时间被选择
  672. const betweenTime = ref(null)
  673. const betweenDateUpdate = ({ val, arr }) => {
  674. betweenTime.value = arr
  675. searchLogForm.value.startTime = val?.start
  676. searchLogForm.value.endTime = val?.end
  677. }
  678. //回车搜索
  679. const keyUpEvent = (e) => {
  680. if (e.key === 'Enter') {
  681. searchLogForm.value.current = 1
  682. getLogTableData()
  683. }
  684. }
  685. //搜索
  686. const searchClick = () => {
  687. searchLogForm.value.current = 1
  688. getLogTableData()
  689. }
  690. //分页被点击
  691. const pageLogChange = ({ current, size }) => {
  692. searchLogForm.value.current = current
  693. searchLogForm.value.size = size
  694. getLogTableData()
  695. }
  696. //获取数据
  697. const logTableLoading = ref(false)
  698. const getLogTableData = async () => {
  699. logTableLoading.value = true
  700. const { error, code, data } = await userApi.getOperationLog({
  701. projectId: projectId.value,
  702. contractId: contractId.value,
  703. ...searchLogForm.value,
  704. })
  705. logTableLoading.value = false
  706. if (!error && code === 200) {
  707. logTableData.value = getArrValue(data['records'])
  708. searchLogForm.value.total = data.total || 0
  709. } else {
  710. logTableData.value = []
  711. searchLogForm.value.total = 0
  712. }
  713. }
  714. //查看日志内容
  715. const operationContentModal = ref(false)
  716. const operationContent = ref('')
  717. const saveData = ref('')
  718. const tableOperationContent = (row) => {
  719. operationContent.value = row['operationContent'] ?? ''
  720. saveData.value = row['saveData']
  721. operationContentModal.value = true
  722. }
  723. //个人和全部切换
  724. const userTypeKey = ref('1')
  725. const userTypeTab = ref([{ key: '1', name: '个人' }, { key: '2', name: '全部' }])
  726. const userTypeChange = (item) => {
  727. userTypeKey.value = item?.key
  728. if (item?.key === '1') {
  729. searchRecycleForm.value.createUserName = ''
  730. } else {
  731. searchRecycleForm.value.createUserName = 'ALL'
  732. }
  733. getRecycleTableData()
  734. }
  735. //结构类型tab数据和相关处理
  736. const tabTypeKey = ref('1')
  737. const tabTypeTab = ref([
  738. { key: '1', name: '删除台账' },
  739. { key: '2', name: '恢复台账' },
  740. ])
  741. const tabTypeChange = (item) => {
  742. tabTypeKey.value = item?.key
  743. tabTypeKey.value = item?.key
  744. searchRecycleForm.value.current = 1
  745. searchRecycleForm.value.delType = item?.key
  746. getRecycleTableData()
  747. recycleTableColumn.value = tabTypeKey.value === '1' ? recycleTableColumn1 : recycleTableColumn2
  748. }
  749. //搜索和分页数据
  750. const searchRecycleForm = ref({
  751. projectId: projectId.value, contractId: contractId.value, createUserName: '',
  752. delType: tabTypeKey.value, current: 1, size: 20, total: 0,
  753. })
  754. //表格数据
  755. const recycleTableRef = ref(null)
  756. const recycleTableColumn = ref([
  757. { key: 'fileName', name: '删除位置' },
  758. { key: 'fileName', name: '工程划分' },
  759. { key: 'fileName', name: '是否资料节点', width: '100' },
  760. { key: 'fileName', name: '文件题名(施工)' },
  761. { key: 'fileName', name: '文件题名(监理)' },
  762. { key: 'createUserName', name: '删除人' },
  763. { key: 'operationTime', name: '删除时间', align: 'center', width: '180' },
  764. { key: 'action', name: '操作', width: '80' },
  765. ])
  766. const recycleTableColumn1 = [
  767. { key: 'fileName', name: '删除位置' },
  768. { key: 'fileName', name: '工程划分' },
  769. { key: 'fileName', name: '是否资料节点', width: '100' },
  770. { key: 'fileName', name: '文件题名(施工)' },
  771. { key: 'fileName', name: '文件题名(监理)' },
  772. { key: 'createUserName', name: '删除人' },
  773. { key: 'operationTime', name: '删除时间', align: 'center', width: '180' },
  774. { key: 'action', name: '操作', width: '80' },
  775. ]
  776. const recycleTableColumn2 = [
  777. { key: 'fileName', name: '删除位置' },
  778. { key: 'fileName', name: '工程划分' },
  779. { key: 'fileName', name: '是否资料节点', width: '100' },
  780. { key: 'fileName', name: '文件题名(施工)' },
  781. { key: 'fileName', name: '文件题名(监理)' },
  782. { key: 'createUserName', name: '恢复人' },
  783. { key: 'operationTime', name: '恢复时间', align: 'center', width: '180' },
  784. { key: 'createUserName', name: '删除信息' },
  785. ]
  786. const recycleTableLoading = ref(false)
  787. const recycleTableData = ref([
  788. { fileName: '文件名', createUserName: '创建人', operationTime: '操作时间' },
  789. { fileName: '文件名', createUserName: '创建人', operationTime: '操作时间' },
  790. ])
  791. //分页被点击
  792. const pageRecycleChange = ({ current, size }) => {
  793. searchRecycleForm.value.current = current
  794. searchRecycleForm.value.size = size
  795. getRecycleTableData()
  796. }
  797. //获取数据
  798. const getRecycleTableData = async () => {
  799. // const { error, code, data } = await userApi.queryRecycleBinList({
  800. // projectId: projectId.value,
  801. // contractId: contractId.value,
  802. // delType: tabTypeKey.value,
  803. // ...searchRecycleForm.value,
  804. // })
  805. // if (!error && code === 200) {
  806. // recycleTableData.value = getArrValue(data['records'])
  807. // searchRecycleForm.value.total = data.total || 0
  808. // } else {
  809. // recycleTableData.value = []
  810. // searchRecycleForm.value.total = 0
  811. // }
  812. }
  813. //多选
  814. const RecycleCheckedKeys = ref([])
  815. const recycleTableSelectionChange = (val) => {
  816. RecycleCheckedKeys.value = val
  817. }
  818. //恢复
  819. const recycleBtnLoading = ref(false)
  820. const recycleBtnClick = async () => {
  821. const rows = RecycleCheckedKeys.value
  822. let hasUnoperableData = false
  823. // 遍历每一行数据,检查 status 字段
  824. for (const row of rows) {
  825. if (row.status === 2) {
  826. hasUnoperableData = true
  827. break
  828. }
  829. }
  830. // 如果存在 status = 2 的数据,则提示用户并返回
  831. if (hasUnoperableData) {
  832. window.$message.warning('存在不可操作的数据,请检查后再操作。')
  833. return
  834. }
  835. if (rows.length > 0) {
  836. //请求数据
  837. recycleBtnLoading.value = true
  838. const { error, code, msg } = await userApi.recycleBinRegain({
  839. projectId: projectId.value,
  840. contractId: contractId.value,
  841. delType: tabTypeKey.value,
  842. regainIds: rows,
  843. })
  844. recycleBtnLoading.value = false
  845. if (!error && code === 200) {
  846. window?.$message?.success('操作成功')
  847. searchRecycleForm.value.current = 1
  848. getRecycleTableData()
  849. } else {
  850. window?.$message?.error(msg || '操作失败')
  851. }
  852. } else {
  853. window.$message?.warning('请先勾选要恢复的数据')
  854. }
  855. }
  856. const tabBetweenTime = ref(null)
  857. const searchRecleForm = ref({
  858. })
  859. const userData = ref([])
  860. //日期时间被选择
  861. const tabBetweenTimeUpdate = ({ arr, val, query }) => {
  862. betweenTime.value = arr
  863. console.log('val', val)
  864. console.log('arr', arr)
  865. console.log('query', query)
  866. }
  867. const searchRecleClick = () => {
  868. // getRecycleTableData()
  869. }
  870. const recoverModal = ref(false)
  871. const recoverClick = (row)=>{
  872. console.log(row, 'row')
  873. recoverModal.value = true
  874. if (RecycleCheckedKeys.value.length === 0) {
  875. cheVal.value = [row]
  876. } else {
  877. cheVal.value = RecycleCheckedKeys.value
  878. }
  879. }
  880. const cheVal = ref([])
  881. </script>
  882. <style lang="scss" scoped>
  883. @import "../../styles/user/index.scss";
  884. </style>
  885. <style lang="scss">
  886. .user-avatar-upload .upload-dom, .upload-dom .el-upload {
  887. height: 100%;
  888. width: 100%;
  889. }
  890. </style>