edit.vue 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. <template>
  2. <div class="facilities-dialog-container">
  3. <van-popup
  4. v-model:show="state.dialog.isShowDialog"
  5. position="bottom"
  6. round
  7. :style="{ height: '90%' }"
  8. close-on-popstate
  9. >
  10. <div class="vant-dialog">
  11. <header class="vant-dialog__header">
  12. <h4>{{ state.dialog.title }}</h4>
  13. </header>
  14. <main class="vant-dialog__body">
  15. <section class="section">
  16. <van-cell-group inset>
  17. <h5 class="section__title">申请信息</h5>
  18. <van-cell
  19. title="入室申请名称"
  20. :value="`${state.oldForm.userName}的${state.oldForm.platformName}的入室申请`"
  21. />
  22. <van-cell
  23. title="申请平台"
  24. :value="state.oldForm.platformName"
  25. />
  26. <van-cell
  27. title="入室周期"
  28. :title-style="{ flex: '0 0 80px', maxWidth: '80px' }"
  29. :value="`${
  30. state.oldForm?.startTime ? formatDate(new Date(state.oldForm?.startTime), 'YYYY-mm-dd') : ''
  31. } ~ ${state.oldForm?.endTime ? formatDate(new Date(state.oldForm?.endTime), 'YYYY-mm-dd') : ''}`"
  32. />
  33. <van-cell
  34. title="预约房间"
  35. :value="state.oldForm.resName"
  36. />
  37. </van-cell-group>
  38. </section>
  39. <section class="section">
  40. <van-cell-group inset>
  41. <h5 class="section__title">预约信息</h5>
  42. <van-field
  43. label="开始时间"
  44. v-model="state.form.startTime"
  45. readonly
  46. input-align="right"
  47. />
  48. <van-field
  49. label="结束时间"
  50. v-model="state.form.endTime"
  51. readonly
  52. input-align="right"
  53. />
  54. <van-field
  55. label="预约时长"
  56. :model-value="state.form.duration + '分钟'"
  57. readonly
  58. input-align="right"
  59. />
  60. <van-field
  61. v-model="state.form.remark"
  62. label="备注"
  63. type="textarea"
  64. rows="3"
  65. maxlength="200"
  66. show-word-limit
  67. placeholder="请输入备注"
  68. />
  69. </van-cell-group>
  70. </section>
  71. </main>
  72. <van-action-bar
  73. placeholder
  74. safe-area-inset-bottom
  75. >
  76. <van-action-bar-button
  77. text="取消"
  78. type="warning"
  79. @click="onCancel"
  80. />
  81. <van-action-bar-button
  82. type="primary"
  83. color="#2c78ff"
  84. :text="state.dialog.submitTxt || '提交'"
  85. :loading="state.dialog.submitting"
  86. :disabled="state.dialog.submitting"
  87. @click="onSubmit('20')"
  88. />
  89. </van-action-bar>
  90. </div>
  91. </van-popup>
  92. </div>
  93. </template>
  94. <script setup lang="ts" name="systemProDialog">
  95. import { nextTick, reactive, ref } from 'vue'
  96. import to from 'await-to-js'
  97. import moment from 'moment/moment'
  98. import { storeToRefs } from 'pinia'
  99. import { showToast } from 'vant'
  100. import { useSystemApi } from '/@/api/platform/system'
  101. import { deepClone } from '/@/utils/other'
  102. import { useAppointmentApi } from '/@/api/platform/home/appointment'
  103. import { useUserInfo } from '/@/stores/userInfo'
  104. import { formatDate } from '/@/utils/formatTime'
  105. import { useCellAssignApi } from '/@/api/platform/home/assign'
  106. // 定义子组件向父组件传值/事件
  107. const emit = defineEmits(['refresh'])
  108. // 定义变量内容
  109. const Api = useAppointmentApi()
  110. const assignApi = useCellAssignApi()
  111. const systemApi = useSystemApi()
  112. const stores = useUserInfo()
  113. const { userInfos } = storeToRefs(stores)
  114. const state = reactive({
  115. form: {
  116. id: 0,
  117. assignId: 0,
  118. appointId: 0,
  119. userId: 0,
  120. userName: '',
  121. userDeptId: null,
  122. userDeptName: '',
  123. userContact: '',
  124. startTime: null,
  125. endTime: null,
  126. remark: '',
  127. duration: 0,
  128. },
  129. oldForm: {
  130. id: 0,
  131. appointId: 0,
  132. mainId: 0,
  133. platformId: 0,
  134. platformName: '',
  135. resId: 0,
  136. resLocation: '',
  137. resName: '',
  138. userId: 0,
  139. userName: '',
  140. assignStatus: '',
  141. startTime: '',
  142. endTime: '',
  143. oldStartTime: '',
  144. oldEndTime: '',
  145. isConfirm: '',
  146. location: 0,
  147. outApplyTime: '',
  148. outStatus: 0,
  149. outTime: null,
  150. },
  151. dialog: {
  152. isShowDialog: false,
  153. type: '',
  154. title: '',
  155. submitTxt: '',
  156. submitting: false,
  157. },
  158. })
  159. const belongOrgOption = ref<DeptTreeType[]>([])
  160. const userList = ref<any[]>([]) //用户列表
  161. const getDicts = async () => {
  162. await Promise.all([systemApi.getDeptTree(), systemApi.getUserList({ noPage: true })]).then(([dept, user]) => {
  163. belongOrgOption.value = dept?.data || []
  164. userList.value = user?.data.list || []
  165. })
  166. }
  167. // 打开弹窗
  168. const openDialog = async (type: string, row: any) => {
  169. await getDicts()
  170. state.dialog.type = type
  171. state.dialog.title = '使用预约'
  172. if (type == 'add') {
  173. state.form = {
  174. id: row?.id,
  175. assignId: row?.id,
  176. appointId: row?.appointId,
  177. userId: userInfos.value.id,
  178. userName: userInfos.value.nickName,
  179. userDeptId: userInfos.value.deptId,
  180. userDeptName: userInfos.value.deptName,
  181. userContact: userInfos.value.phone,
  182. startTime: row?.startTime,
  183. endTime: row?.endTime,
  184. remark: '',
  185. duration: 0,
  186. }
  187. const [err, res]: ToResponse = await to(assignApi.getDetail({ id: row?.id }))
  188. if (err) return
  189. state.oldForm = res?.data || {}
  190. // 计算startTime和endTime的分钟差
  191. const diff = moment(state.form.endTime).diff(moment(state.form.startTime), 'minutes')
  192. state.form.duration = diff
  193. } else {
  194. const [err, res]: ToResponse = await to(Api.getDetail({ id: row?.id }))
  195. if (err) return
  196. state.form = res?.data || {}
  197. }
  198. state.dialog.submitTxt = '提 交'
  199. state.dialog.isShowDialog = true
  200. // 清空表单,此项需加表单验证才能使用
  201. await nextTick()
  202. }
  203. // 关闭弹窗
  204. const closeDialog = () => {
  205. state.dialog.isShowDialog = false
  206. }
  207. const onCancel = () => {
  208. closeDialog()
  209. }
  210. // 提交
  211. const onSubmit = async (type: string) => {
  212. if (state.dialog.submitting) return
  213. state.dialog.submitting = true
  214. // 基础必填校验(开始/结束时间)
  215. if (!state.form.startTime || !state.form.endTime) {
  216. showToast('开始时间和结束时间不能为空')
  217. state.dialog.submitting = false
  218. return
  219. }
  220. const params: any = deepClone(state.form)
  221. params.isTemporary = type
  222. const post = state.dialog.type == 'add' ? Api.create : Api.updateById
  223. const [err]: ToResponse = await to(post(params))
  224. if (err) {
  225. state.dialog.submitting = false
  226. return
  227. }
  228. showToast('操作成功')
  229. closeDialog()
  230. emit('refresh')
  231. state.dialog.submitting = false
  232. }
  233. // 暴露变量
  234. defineExpose({
  235. openDialog,
  236. })
  237. </script>
  238. <style lang="scss" scoped>
  239. .vant-dialog {
  240. display: flex;
  241. flex-direction: column;
  242. height: 100%;
  243. background-color: #f7f8fa;
  244. &__header {
  245. padding: 12px 16px;
  246. border-bottom: 1px solid #f0f0f0;
  247. h4 {
  248. margin: 0;
  249. font-size: 16px;
  250. font-weight: 600;
  251. }
  252. }
  253. &__body {
  254. flex: 1;
  255. overflow-y: auto;
  256. padding: 12px 0 60px;
  257. }
  258. }
  259. .section {
  260. margin-bottom: 12px;
  261. &__title {
  262. margin: 4px 10px 6px;
  263. font-size: 13px;
  264. color: #969799;
  265. }
  266. }
  267. :deep(.disUoloadSty .el-upload--picture-card) {
  268. display: none; /* 上传按钮隐藏 */
  269. }
  270. .avatar-uploader {
  271. :deep(.el-upload) {
  272. width: 100%;
  273. height: 100%;
  274. border: 1px dashed var(--el-border-color);
  275. border-radius: 6px;
  276. cursor: pointer;
  277. position: relative;
  278. overflow: hidden;
  279. transition: var(--el-transition-duration-fast);
  280. &:hover {
  281. border-color: var(--el-color-primary);
  282. }
  283. }
  284. }
  285. .el-icon.avatar-uploader-icon {
  286. font-size: 28px;
  287. color: #8c939d;
  288. width: 178px;
  289. height: 178px;
  290. text-align: center;
  291. }
  292. </style>