mine.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <template>
  2. <div class="entry-container">
  3. <div class="list-container">
  4. <div
  5. class="search-wrap"
  6. ref="searchWrapRef"
  7. >
  8. <el-form
  9. :model="state.queryParams"
  10. ref="queryRef"
  11. :inline="true"
  12. >
  13. <el-form-item prop="serialNo">
  14. <el-select
  15. v-model="state.queryParams.platformId"
  16. style="width: 100%"
  17. placeholder="申请平台"
  18. clearable
  19. @change="search"
  20. >
  21. <el-option
  22. v-for="item in platformList"
  23. :key="item.id"
  24. :label="item.platformName"
  25. :value="item.id"
  26. ></el-option>
  27. </el-select>
  28. </el-form-item>
  29. <el-form-item prop="serialNo">
  30. <div class="flex justify-between">
  31. <el-date-picker
  32. v-model="startTime"
  33. style="width: 48%"
  34. type="date"
  35. placeholder="开始时间"
  36. clearable
  37. @change="search"
  38. />
  39. <el-date-picker
  40. v-model="endTime"
  41. style="width: 48%"
  42. type="date"
  43. placeholder="结束时间"
  44. clearable
  45. @change="search"
  46. />
  47. </div>
  48. </el-form-item>
  49. <el-form-item prop="serialNo">
  50. <el-input
  51. v-model="state.queryParams.resName"
  52. style="width: 100%"
  53. placeholder="资源名称"
  54. clearable
  55. @keyup.enter="search"
  56. />
  57. </el-form-item>
  58. </el-form>
  59. </div>
  60. <van-list
  61. v-model:loading="state.loading"
  62. :finished="state.finished"
  63. finished-text="没有更多了"
  64. @load="onLoad"
  65. >
  66. <van-cell
  67. v-for="item in state.list"
  68. :key="item"
  69. >
  70. <template #default>
  71. <div class="list">
  72. <header class="flex justify-between">
  73. <strong class="title">{{ item.userName }}的{{ item.platformName }}入室申请</strong>
  74. <van-tag
  75. v-if="item.assignStatus == EntryAssignStatus.TO_BE_ENTERED"
  76. type="primary"
  77. >
  78. 待入室
  79. </van-tag>
  80. <van-tag
  81. v-else-if="item.assignStatus == EntryAssignStatus.NEXT_MONTH_ENTERED"
  82. type="primary"
  83. >
  84. 次月入室
  85. </van-tag>
  86. <van-tag
  87. v-else-if="item.assignStatus == EntryAssignStatus.ENTERED"
  88. type="success"
  89. >
  90. 已入室
  91. </van-tag>
  92. <van-tag
  93. v-else-if="item.assignStatus == EntryAssignStatus.OUT_ROOM"
  94. type="primary"
  95. >
  96. 已出室
  97. </van-tag>
  98. <van-tag
  99. v-else-if="item.assignStatus == EntryAssignStatus.NEXT_MONTH_OUT_ROOM"
  100. type="primary"
  101. >
  102. 次月出室
  103. </van-tag>
  104. </header>
  105. <p class="inst-title">
  106. <span>申请平台</span>
  107. <span class="title ml8">
  108. {{ item.platformName }}
  109. </span>
  110. </p>
  111. <p class="inst-title">
  112. <span>入室时间</span>
  113. <span class="title ml8">
  114. {{ item?.startTime ? formatDate(new Date(item?.startTime), 'YYYY-mm-dd') : '' }}
  115. ~
  116. {{ item?.endTime ? formatDate(new Date(item?.endTime), 'YYYY-mm-dd') : '' }}
  117. </span>
  118. </p>
  119. <p class="inst-title">
  120. <span>资源名称</span>
  121. <span class="title ml8">
  122. {{ item.resName }}
  123. </span>
  124. </p>
  125. <p class="inst-title">
  126. <span>位置信息</span>
  127. <span class="title ml8">
  128. {{ item.resLocation }}
  129. </span>
  130. </p>
  131. <footer class="flex justify-between mt16">
  132. <div
  133. v-if="item.assignStatus === '20' && item.userId === userInfos.id"
  134. style="text-align: right; width: 100%"
  135. >
  136. <van-button
  137. type="primary"
  138. style="height: 30px"
  139. @click="handleAppointment(item)"
  140. >
  141. 使用预约
  142. </van-button>
  143. </div>
  144. <div
  145. v-if="
  146. item.assignStatus === '20' &&
  147. item.userId === userInfos.id &&
  148. item.outStatus !== 20 &&
  149. item.outStatus !== 30
  150. "
  151. style="text-align: right; width: 100%"
  152. >
  153. <van-button
  154. type="primary"
  155. style="height: 30px"
  156. @click="handleRenewal(item)"
  157. >
  158. 申请续期
  159. </van-button>
  160. </div>
  161. <div
  162. v-if="item.assignStatus === EntryAssignStatus.ENTERED && item.userId === userInfos.id"
  163. style="text-align: right; width: 100%"
  164. >
  165. <van-button
  166. type="primary"
  167. style="height: 30px"
  168. @click="handleOutRoom(item)"
  169. >
  170. 申请出室
  171. </van-button>
  172. </div>
  173. </footer>
  174. </div>
  175. </template>
  176. </van-cell>
  177. </van-list>
  178. </div>
  179. <el-dialog
  180. v-model="showOutDialog"
  181. title="申请出室"
  182. width="85%"
  183. :before-close="
  184. () => {
  185. showOutDialog = false
  186. }
  187. "
  188. >
  189. <el-form
  190. ref="outRoomFormRef"
  191. :model="outRoomForm"
  192. :rules="rules"
  193. label-position="top"
  194. >
  195. <el-form-item
  196. style="display: block"
  197. label="申请出室日期"
  198. prop="outRoomDate"
  199. >
  200. <el-date-picker
  201. :disabled-date="disabledTime"
  202. v-model="outRoomForm.outRoomDate"
  203. type="month"
  204. style="width: 100%"
  205. placeholder="请选择出室月份"
  206. value-format="YYYY-MM-DD"
  207. />
  208. </el-form-item>
  209. <el-form-item>
  210. <div style="text-align: right; width: 100%">
  211. <el-button
  212. @click="
  213. () => {
  214. showOutDialog = false
  215. }
  216. "
  217. >
  218. 取消
  219. </el-button>
  220. <el-button
  221. type="primary"
  222. @click="handleSubmitOutRoom"
  223. >
  224. 申请
  225. </el-button>
  226. </div>
  227. </el-form-item>
  228. </el-form>
  229. </el-dialog>
  230. <Appoint ref="appointRef" />
  231. <RenewalEdit ref="renewalEditRef" />
  232. </div>
  233. </template>
  234. <script name="entryMine" lang="ts" setup>
  235. import { reactive, onMounted, ref } from 'vue'
  236. import { useRouter } from 'vue-router'
  237. import to from 'await-to-js'
  238. import { storeToRefs } from 'pinia'
  239. import { ElMessage } from 'element-plus'
  240. import dayjs from 'dayjs'
  241. import { usePlatformAppointApi } from '/@/api/platform/appoint'
  242. import { useCellAssignApi } from '/@/api/platform/home/assign'
  243. import { usePlatformApi } from '/@/api/platform/home'
  244. import { formatDate } from '/@/utils/formatTime'
  245. import { useUserInfo } from '/@/stores/userInfo'
  246. import Appoint from './components/appoint.vue'
  247. import RenewalEdit from './components/renewalEdit.vue'
  248. enum EntryAssignStatus {
  249. TO_BE_ENTERED = '10', // 待入室
  250. NEXT_MONTH_ENTERED = '15', // 次月入室
  251. ENTERED = '20', // 已入室
  252. OUT_ROOM = '30', // 已出室
  253. NEXT_MONTH_OUT_ROOM = '40', // 次月出室
  254. }
  255. const stores = useUserInfo()
  256. const { userInfos } = storeToRefs(stores)
  257. const platformAppointApi = usePlatformAppointApi()
  258. const platformApi = usePlatformApi()
  259. const cellAssignApi = useCellAssignApi()
  260. const router = useRouter()
  261. const outRoomFormRef = ref()
  262. const renewalEditRef = ref()
  263. const appointRef = ref()
  264. const showOutDialog = ref<boolean>(false)
  265. const startTime = ref('')
  266. const endTime = ref('')
  267. const platformList = ref<any[]>([])
  268. const state = reactive({
  269. queryParams: {
  270. platformId: null,
  271. dateTime: [],
  272. resName: '',
  273. pageNum: 1,
  274. orderBy: '',
  275. pageSize: 20,
  276. },
  277. finished: false,
  278. loading: true,
  279. list: [] as any[],
  280. })
  281. const currentSelectEntryItem = ref({
  282. id: null,
  283. endTime: '',
  284. startTime: '',
  285. })
  286. const outRoomForm = reactive({
  287. outRoomDate: '',
  288. })
  289. const rules = {
  290. outRoomDate: { required: true, message: '不能为空', trigger: 'change' },
  291. }
  292. const disabledTime = (date: Date) => {
  293. let startTime = formatDate(
  294. new Date(dayjs(currentSelectEntryItem.value.startTime).add(1, 'month').format('YYYY-MM-DD')),
  295. 'YYYY-mm-dd',
  296. )
  297. let endTime = formatDate(
  298. new Date(dayjs(currentSelectEntryItem.value.endTime).subtract(1, 'month').format('YYYY-MM-DD')),
  299. 'YYYY-mm-dd',
  300. )
  301. let now = formatDate(new Date(), 'YYYY-mm-dd')
  302. let time = formatDate(new Date(date), 'YYYY-mm-dd')
  303. return time < now || time > endTime || time < startTime
  304. }
  305. const onLoad = async () => {
  306. state.loading = true
  307. const payload: any = {
  308. ...state.queryParams,
  309. }
  310. Object.keys(payload).map((item) => {
  311. if (payload[item] === '' || payload[item] === null) {
  312. delete payload[item]
  313. }
  314. })
  315. const [err, res]: ToResponse = await to(cellAssignApi.getUserAssignResources(payload))
  316. if (err) return
  317. const list = res?.data?.list || []
  318. for (const item of list) {
  319. state.list.push(item)
  320. }
  321. state.loading = false
  322. state.queryParams.pageNum++
  323. if (list.length < state.queryParams.pageSize) {
  324. state.finished = true
  325. }
  326. }
  327. const getDicts = () => {
  328. Promise.all([platformApi.getPlatformList()]).then(([plat]) => {
  329. platformList.value = plat?.data?.list || []
  330. })
  331. }
  332. const resetQuery = () => {
  333. state.queryParams = {
  334. ...state.queryParams,
  335. pageNum: 1,
  336. pageSize: 20,
  337. }
  338. state.list = []
  339. state.finished = false
  340. state.loading = true
  341. }
  342. const search = () => {
  343. if (startTime.value) {
  344. state.queryParams.dateTime[0] = startTime.value
  345. } else {
  346. state.queryParams.dateTime[0] = ''
  347. }
  348. if (endTime.value) {
  349. state.queryParams.dateTime[1] = endTime.value
  350. } else {
  351. state.queryParams.dateTime[1] = ''
  352. }
  353. resetQuery()
  354. onLoad()
  355. }
  356. const handleOutRoom = (item: any) => {
  357. showOutDialog.value = true
  358. currentSelectEntryItem.value = item
  359. }
  360. const handleSubmitOutRoom = () => {
  361. outRoomFormRef.value.validate(async (valid: boolean) => {
  362. if (!valid) return
  363. const { projectGroup } = userInfos.value
  364. const [err, res]: ToResponse = await to(
  365. platformAppointApi.createCommonAppoint({
  366. tranId: currentSelectEntryItem.value.id,
  367. tranType: 1,
  368. outApplyTime: dayjs(outRoomForm.outRoomDate).endOf('month').format('YYYY-MM-DD HH:mm:ss'),
  369. memberId: userInfos.value.id,
  370. memberName: userInfos.value.nickName,
  371. memberType: userInfos.value.userType,
  372. memberPhone: userInfos.value.phone,
  373. deptId: userInfos.value.deptId,
  374. deptName: userInfos.value.deptName,
  375. pgId: projectGroup.id,
  376. pgName: projectGroup.pgName,
  377. mentorId: projectGroup.pgLeaderId,
  378. mentorName: projectGroup.pgLeaderName,
  379. mentorDeptName: projectGroup.pgOrgPaths,
  380. mentorPhone: projectGroup.pgLeaderContact,
  381. isTemporary: '20', // 是否暂存,10是,20否
  382. }),
  383. )
  384. if (err) return
  385. showOutDialog.value = false
  386. ElMessage.success('操作成功')
  387. state.list = []
  388. state.queryParams.pageNum = 1
  389. onLoad()
  390. })
  391. }
  392. const handleAppointment = (item: any) => {
  393. appointRef.value.openDialog(item)
  394. }
  395. const handleRenewal = (row) => {
  396. renewalEditRef.value.openDialog('add', row)
  397. }
  398. onMounted(() => {
  399. getDicts()
  400. onLoad()
  401. })
  402. </script>
  403. <style lang="scss" scoped>
  404. .entry-container {
  405. position: relative;
  406. display: flex;
  407. flex-direction: column;
  408. .list-container {
  409. overflow-y: auto;
  410. padding: 10px;
  411. border-radius: 4px;
  412. flex: 1;
  413. }
  414. .van-list {
  415. .van-cell {
  416. background-color: #fff;
  417. + .van-cell {
  418. margin-top: 10px;
  419. }
  420. header,
  421. footer {
  422. color: #333;
  423. }
  424. .title {
  425. flex: 1;
  426. white-space: nowrap;
  427. overflow: hidden;
  428. text-overflow: ellipsis;
  429. text-align: left;
  430. }
  431. .inst-title {
  432. color: #333;
  433. text-align: left;
  434. flex: 1;
  435. overflow: hidden;
  436. white-space: nowrap;
  437. text-overflow: ellipsis;
  438. margin-top: 4px;
  439. span:first-child {
  440. color: rgb(120, 120, 120);
  441. }
  442. }
  443. .time {
  444. color: #f69a4d;
  445. }
  446. }
  447. }
  448. .asterisk-left {
  449. display: flex;
  450. margin-right: 0;
  451. }
  452. .search-wrap {
  453. background: #fff;
  454. margin-bottom: 10px;
  455. padding: 15px;
  456. }
  457. }
  458. </style>