add.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <!--
  2. * @Author: wanglj wanglijie@dashoo.cn
  3. * @Date: 2025-03-18 20:02:42
  4. * @LastEditors: wanglj wanglijie@dashoo.cn
  5. * @LastEditTime: 2025-03-21 09:46:32
  6. * @FilePath: \labsop_h5\src\view\training\enroll.vue
  7. * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  8. -->
  9. <template>
  10. <div class="app-container">
  11. <van-form ref="formRef" @submit="onSubmit" class="mt10" required="auto">
  12. <h4 class="mb8 mt8">设备信息</h4>
  13. <van-cell-group>
  14. <van-field
  15. v-model="state.form.equipmentName"
  16. label="设备名称"
  17. placeholder="设备名称"
  18. @click="openSelectInst"
  19. :rules="[{ required: true, message: '请选择仪器' }]"
  20. />
  21. <van-field v-model="state.form.equipmentCode" label="设备编号" placeholder="设备编号" readonly />
  22. <van-field v-model="state.form.equipmentModel" label="设备型号" placeholder="设备型号" readonly />
  23. <van-field v-model="state.form.equipmentManager" label="设备负责人" placeholder="设备负责人" readonly />
  24. <van-field v-model="state.form.equipmentLocation" label="存放位置" placeholder="存放位置" readonly />
  25. <van-field v-model="state.form.recordName" label="预约记录" placeholder="预约记录" @click="openSelectUsedRecord" />
  26. </van-cell-group>
  27. <h4 class="mb8 mt8">报修信息</h4>
  28. <van-cell-group>
  29. <van-field v-model="state.form.repairApplicantName" label="报修人" placeholder="报修人" :rules="[{ required: true }]" />
  30. <van-field
  31. v-model="state.form.repairDate"
  32. label="报修时间"
  33. placeholder="报修时间"
  34. :rules="[{ required: true, message: '请选择报修时间' }]"
  35. @click="showAddDatePicker = true"
  36. readonly
  37. />
  38. <van-field
  39. v-model="state.form.faultDesc"
  40. rows="3"
  41. autosize
  42. type="textarea"
  43. maxlength="200"
  44. show-word-limit
  45. label="故障说明"
  46. placeholder="故障说明"
  47. :rules="[{ required: true, message: '请输入故障说明' }]"
  48. />
  49. <van-field name="uploader" label="文件上传" :rules="[{ required: true, message: '请上传故障照片' }]">
  50. <template #input>
  51. <van-uploader v-model="state.form.faultPhoto" :after-read="afterRead" preview-size="60" :preview-full-image="true" :max-count="6" />
  52. </template>
  53. </van-field>
  54. </van-cell-group>
  55. <van-action-bar placeholder>
  56. <van-action-bar-icon icon="wap-home-o" text="首页" @click="router.push('/home')" />
  57. <van-action-bar-icon icon="revoke" text="返回" @click="router.push('/inst/repairReport/home')" />
  58. <van-action-bar-button type="primary" text="立即提交" :loading="loading" native-type="submit" />
  59. </van-action-bar>
  60. </van-form>
  61. </div>
  62. <SelectInstPopup ref="SelectInstRef" @selectInst="getSelectInst"></SelectInstPopup>
  63. <SelectInstAppointRecordPopup ref="usedRecordRef" @selectUseRecord="getSelectUsedRecord"></SelectInstAppointRecordPopup>
  64. <!-- 所在时间 -->
  65. <van-popup v-model:show="showAddDatePicker" position="bottom">
  66. <van-date-picker v-model="date" title="选择日期" @confirm="onConfirmDate" :max-date="maxDate" @cancel="showAddDatePicker = false" />
  67. </van-popup>
  68. </template>
  69. <script name="repairReportConfirm" lang="ts" setup>
  70. import to from 'await-to-js'
  71. import { onMounted, reactive, ref, defineAsyncComponent } from 'vue'
  72. import { storeToRefs } from 'pinia'
  73. import { useUserInfo } from '/@/stores/userInfo'
  74. import { showNotify } from 'vant'
  75. import { formatDate } from '/@/utils/formatTime'
  76. import { useRouter } from 'vue-router'
  77. import { handleUpload } from '/@/utils/upload'
  78. import { useRepairReportApi } from '/@/api/instr/repairReport'
  79. const SelectInstPopup = defineAsyncComponent(() => import('/@/components/select-inst.vue'))
  80. const SelectInstAppointRecordPopup = defineAsyncComponent(() => import('/@/components/select-inst-appoint-record.vue'))
  81. const SelectInstRef = ref()
  82. const usedRecordRef = ref()
  83. const repairReportApi = useRepairReportApi()
  84. const storesUseUserInfo = useUserInfo()
  85. const router = useRouter()
  86. const { userInfos } = storeToRefs(storesUseUserInfo)
  87. const formRef = ref()
  88. const state = reactive({
  89. form: {
  90. id: 0,
  91. equipmentCode: '', //设备编码 string
  92. equipmentId: '', //关联设备 integer
  93. equipmentLocation: '', //设备存放位置 string
  94. equipmentManager: '', //设备负责人(带电话) string
  95. equipmentModel: '', //设备型号(带品牌) string
  96. equipmentName: '', //设备名称 string
  97. recordId: 0,
  98. recordName: '',
  99. repairApplicantName: '', //报修人
  100. repairDate: formatDate(new Date(), 'YYYY-mm-dd'), //报修时间 DATETIME string
  101. faultDesc: '', //故障说明 string
  102. faultPhoto: <any>[], //故障照片 string
  103. remark: '' //备注 string
  104. }
  105. })
  106. const loading = ref(false) // 加载状态
  107. const initForm = async () => {
  108. state.form = {
  109. id: 0,
  110. equipmentCode: '', //设备编码 string
  111. equipmentId: '', //关联设备 integer
  112. equipmentLocation: '', //设备存放位置 string
  113. equipmentManager: '', //设备负责人(带电话) string
  114. equipmentModel: '', //设备型号(带品牌) string
  115. equipmentName: '', //设备名称 string
  116. recordId: 0,
  117. recordName: '',
  118. repairApplicantName: '', //报修人
  119. repairDate: formatDate(new Date(), 'YYYY-mm-dd'), //报修时间 DATETIME string
  120. faultDesc: '', //故障说明 string
  121. faultPhoto: <any>[], //故障照片 string
  122. remark: '' //备注 string
  123. }
  124. date.value = [new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()]
  125. console.log(userInfos.value)
  126. state.form.repairApplicantName = userInfos.value.nickName // 报修人
  127. }
  128. const date = ref([]) // 选择的日期
  129. const maxDate = ref(new Date()) // 最大日期
  130. const showAddDatePicker = ref(false) // 是否显示选择日期的弹窗
  131. const onSubmit = async () => {
  132. console.log('提交表单')
  133. const [errValid] = await to(formRef.value.validate())
  134. if (errValid) return
  135. let params = JSON.parse(JSON.stringify(state.form))
  136. console.log(params)
  137. const files = params.faultPhoto.map((item: any) => {
  138. return {
  139. name: item.name,
  140. url: item.url
  141. }
  142. })
  143. params.faultPhoto = JSON.stringify(files) // 将图片数组转换为符合后端要求的格式
  144. loading.value = true
  145. const [err, res]: ToResponse = await to(repairReportApi.create(params))
  146. loading.value = false
  147. if (err) return
  148. showNotify({
  149. type: 'success',
  150. message: '报修申请已提交,请耐心等待处理'
  151. })
  152. setTimeout(() => {
  153. router.push('/inst/repairReport/home')
  154. }, 1000)
  155. }
  156. const openSelectInst = () => {
  157. SelectInstRef.value.openPopup()
  158. }
  159. const openSelectUsedRecord = () => {
  160. if (state.form.equipmentId === '') {
  161. showNotify({
  162. type: 'warning',
  163. message: '请先选择设备'
  164. })
  165. return
  166. }
  167. usedRecordRef.value.openPopup(state.form.equipmentId)
  168. }
  169. const getSelectInst = (data: any) => {
  170. console.log(data)
  171. state.form.equipmentCode = data.instCode //设备编码 string
  172. state.form.equipmentId = data.id //关联设备 integer
  173. state.form.equipmentLocation = data.placeAddress //设备存放位置 string
  174. state.form.equipmentManager = data.instHeadName + '-' + data.instHeadTel //设备负责人(带电话) string
  175. state.form.equipmentModel = data.instNameEn //设备型号(带品牌) string
  176. state.form.equipmentName = data.instName //设备名称 string};
  177. state.form.recordId = 0
  178. state.form.recordName = '' //预约记录
  179. }
  180. const getSelectUsedRecord = (data: any) => {
  181. console.log(data)
  182. state.form.recordId = data.id
  183. state.form.recordName = data.createdName
  184. }
  185. const onConfirmDate = () => {
  186. showAddDatePicker.value = false
  187. state.form.repairDate = `${date.value[0]}-${date.value[1]}-${date.value[2]}`
  188. }
  189. const afterRead = async (files: any) => {
  190. if (files.length) {
  191. for (const file of files) {
  192. file.status = 'uploading'
  193. const [err, res]: ToResponse = await to(handleUpload(file.file))
  194. if (err) {
  195. file.status = 'failed'
  196. return
  197. }
  198. file.status = 'success'
  199. file.url = res
  200. file.name = file.file.name
  201. }
  202. } else {
  203. const file = files
  204. file.status = 'uploading'
  205. const [err, res]: ToResponse = await to(handleUpload(file.file))
  206. if (err) {
  207. file.status = 'failed'
  208. return
  209. }
  210. file.status = 'success'
  211. file.url = res
  212. file.name = file.file.name
  213. }
  214. }
  215. onMounted(async () => {
  216. initForm()
  217. })
  218. </script>
  219. <style lang="scss" scoped>
  220. .app-container {
  221. header {
  222. padding: 14px;
  223. background-color: #f9ffff;
  224. border-radius: 4px;
  225. margin-top: 10px;
  226. }
  227. h4 {
  228. margin: 10px 0;
  229. height: 20px;
  230. line-height: 20px;
  231. &::before {
  232. display: inline-block;
  233. content: '';
  234. background-color: #3c78e3;
  235. width: 4px;
  236. height: 20px;
  237. margin-right: 4px;
  238. vertical-align: top;
  239. }
  240. }
  241. :deep(.flow-cell) {
  242. margin-left: 22px;
  243. display: flex;
  244. justify-content: space-between;
  245. color: #333;
  246. }
  247. }
  248. .ck-editor {
  249. height: calc(100vh - 100px);
  250. overflow-y: auto;
  251. padding: 0 10px;
  252. }
  253. .need-to-know {
  254. height: calc(100% - 20px);
  255. overflow: hidden;
  256. display: flex;
  257. flex-direction: column;
  258. padding: 10px 20px;
  259. white-space: pre-wrap;
  260. p {
  261. flex: 1;
  262. overflow-y: auto;
  263. }
  264. footer {
  265. flex: 0 0 45px;
  266. margin-top: 4px;
  267. border-top: 1px solid #f7f8fa;
  268. }
  269. }
  270. </style>