image-form.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. <template>
  2. <div class="hc-layout-box">
  3. <div v-if="dataType === 1" :style="`width:${leftWidth}px;`" class="hc-layout-left-box">
  4. <div class="hc-project-box">
  5. <div class="hc-project-icon-box">
  6. <HcIcon name="stack" />
  7. </div>
  8. <div class="ml-2 project-name-box">
  9. <span class="text-xl text-cut project-alias">{{ projectInfo.projectAlias }}</span>
  10. <div class="text-xs text-cut project-name">{{ projectInfo.name }}</div>
  11. </div>
  12. </div>
  13. <div class="hc-tree-box">
  14. <el-scrollbar>
  15. <WbsTree
  16. :auto-expand-keys="TreeAutoExpandKeys" :contract-id="contractId" :project-id="projectId" :class-id="classifyId"
  17. @nodeTap="nodeWbsElTreeClick"
  18. />
  19. </el-scrollbar>
  20. </div>
  21. <!-- 左右拖动 -->
  22. <div class="horizontal-drag-line" @mousedown="onmousedown" />
  23. </div>
  24. <div v-loading="queryByLoading" class="hc-layout-content-box" element-loading-text="获取数据中...">
  25. <HcCard
  26. :scrollbar="false"
  27. :title="`${treeItemInfo?.title ?? ''} 上传${fileType === 1 ? '视频' : fileType === 2 ? '图片' : ''}`"
  28. action-size="lg"
  29. >
  30. <el-alert
  31. v-if="dataType === 1 && !wbsId" :closable="false" effect="dark" style="margin-bottom: 14px"
  32. title="请先在左边项目树,选择一个节点" type="warning"
  33. />
  34. <el-row :gutter="20" class="hc-form-row-box">
  35. <el-col :span="10">
  36. <el-scrollbar>
  37. <el-form ref="formRef" :model="formValue" :rules="rules" label-width="auto" size="large">
  38. <el-form-item label="上传日期" prop="uploadTime">
  39. <el-date-picker
  40. v-model="formValue.uploadTime" format="YYYY-MM-DD" type="date"
  41. value-format="YYYY-MM-DD"
  42. />
  43. </el-form-item>
  44. <el-form-item label="上传文件" prop="imageUrl">
  45. <div class="w-full">
  46. <HcUploads
  47. :accept="fileType === 1 ? videoAccept : fileType === 2 ? imageAccept : null"
  48. :file-list="uploadFileList"
  49. :limit="fileType === 2 ? 10 : 1"
  50. :size="fileType === 2 ? 30 : 500" :viewer="false"
  51. action="upload-file" @change="uploadsChange" @del="uploadsDel"
  52. @preview="uploadsPreview" @progress="uploadsProgress"
  53. />
  54. </div>
  55. <el-image-viewer
  56. v-if="previewModal && fileType === 2" :initial-index="initialIndex"
  57. :url-list="previewFileList" @close="previewModalClose"
  58. />
  59. <el-dialog
  60. v-model="previewVideoModal" :before-close="previewModalClose"
  61. destroy-on-close
  62. width="62rem"
  63. >
  64. <video
  65. :src="previewVideoUrl" autoplay="autoplay" class="preview-video"
  66. controls="controls"
  67. >
  68. 您的浏览器不支持 video
  69. </video>
  70. </el-dialog>
  71. <el-alert
  72. v-if="fileType === 1"
  73. :closable="false"
  74. title="请上传MP4、MOV格式的视频文件,文件大小不超过500M,只能上传1个视频文件"
  75. type="error"
  76. />
  77. <el-alert
  78. v-if="fileType === 2"
  79. :closable="false"
  80. title="请上传JPG/JPEG、PNG格式的图片文件,文件大小不超过30M,最多10张图片文件"
  81. type="error"
  82. />
  83. </el-form-item>
  84. <el-form-item label="题名" prop="title">
  85. <el-input v-model="formValue.title" placeholder="请输入题名" />
  86. </el-form-item>
  87. <div class="flex">
  88. <el-form-item
  89. :class="fileType === 2 ? 'mr-4' : ''" class="flex-1" label="拍摄者"
  90. prop="shootingUser"
  91. >
  92. <el-input v-model="formValue.shootingUser" placeholder="请输入拍摄者" />
  93. </el-form-item>
  94. <el-form-item v-if="fileType === 2" class="flex-1 ml-4" label="照片号">
  95. <el-input v-model="formValue.photoCode" placeholder="请输入照片号" />
  96. </el-form-item>
  97. </div>
  98. <el-form-item label="拍摄时间" prop="shootingTimeStr">
  99. <el-date-picker
  100. v-model="formValue.shootingTimeStr" format="YYYY-MM-DD" type="date"
  101. value-format="YYYY-MM-DD"
  102. />
  103. </el-form-item>
  104. <div v-if="fileType === 2" class="flex">
  105. <el-form-item class="flex-1 mr-4" label="底片号" prop="filmCode">
  106. <el-input v-model="formValue.filmCode" placeholder="请输入底片号" />
  107. </el-form-item>
  108. <el-form-item class="flex-1 ml-4" label="参见号" prop="seeAlsoCode">
  109. <el-input v-model="formValue.seeAlsoCode" placeholder="请输入参见号" />
  110. </el-form-item>
  111. </div>
  112. <el-form-item label="文字说明" prop="textContent">
  113. <el-input
  114. v-model="formValue.textContent" :autosize="{ minRows: 3, maxRows: 5 }"
  115. placeholder="请输入文字说明" type="textarea"
  116. />
  117. </el-form-item>
  118. </el-form>
  119. </el-scrollbar>
  120. </el-col>
  121. <el-col :span="14">
  122. <HcTable v-if="dataType === 2" :column="tableColumn" :datas="tableData" />
  123. </el-col>
  124. </el-row>
  125. <template #action>
  126. <el-button
  127. :disabled="uploadsLoading || (dataType === 1 && !wbsId)" :loading="saveLoading" hc-btn
  128. type="primary" @click="saveClick"
  129. >
  130. <HcIcon name="save" />
  131. <span>保存</span>
  132. </el-button>
  133. <el-button
  134. v-if="dataType === 2" :disabled="uploadsLoading" :loading="saveLoading" hc-btn
  135. @click="saveLogClick"
  136. >
  137. <HcIcon name="save" />
  138. <span>保存并再次添加</span>
  139. </el-button>
  140. <el-button hc-btn @click="toBackClick">
  141. <HcIcon name="arrow-go-back" />
  142. <span>返回</span>
  143. </el-button>
  144. </template>
  145. </HcCard>
  146. </div>
  147. </div>
  148. </template>
  149. <script setup>
  150. import { onActivated, onMounted, ref, watch } from 'vue'
  151. import { useAppStore } from '~src/store'
  152. import { useRoute, useRouter } from 'vue-router'
  153. import WbsTree from './components/WbsTree.vue'
  154. import imageApi from '~api/other-file/imageData'
  155. import { getStoreValue, setStoreValue } from '~src/utils/storage'
  156. import { arrToKey, deepClone, formValidate, getObjValue, getRandom } from 'js-fast-way'
  157. import { dateFormat } from '~src/utils/tools'
  158. import ossApi from '~api/oss'
  159. //变量
  160. const router = useRouter()
  161. const useRoutes = useRoute()
  162. const useAppState = useAppStore()
  163. const projectId = ref(useAppState.getProjectId)
  164. const contractId = ref(useAppState.getContractId)
  165. const projectInfo = ref(useAppState.getProjectInfo)
  166. const isCollapse = ref(useAppState.getCollapse)
  167. const userInfo = ref(useAppState.getUserInfo)
  168. //路由参数
  169. const routerQuery = useRoutes?.query
  170. //存储目录格式 1按部位存储,2按日期存储
  171. const dataId = ref(routerQuery?.id || '')
  172. const wbsNodeIds = routerQuery?.wbsId || ''
  173. const classifyId = routerQuery?.classifyId || ''
  174. const dataType = parseInt(routerQuery?.dataType + '') || 1
  175. const fileType = parseInt(routerQuery?.fileType + '') || 2
  176. const toDayDate = dateFormat(new Date(), 'yyyy-MM-dd')
  177. const userRealName = ref('')
  178. //监听
  179. watch(() => [
  180. useAppState.getCollapse,
  181. useAppState.getUserInfo,
  182. useAppState.getContractId,
  183. ], ([Collapse, UserInfo, ContractId]) => {
  184. isCollapse.value = Collapse
  185. userRealName.value = UserInfo['real_name']
  186. formValue.value.shootingUser = UserInfo['real_name']
  187. contractId.value = ContractId
  188. })
  189. watch(contractId, (val) => {
  190. if (val) {
  191. router.push({
  192. path: '/other-file/image-data',
  193. })
  194. }
  195. })
  196. //自动展开缓存
  197. const TreeAutoExpandKeys = ref([])
  198. //渲染完成
  199. onActivated(() => {
  200. dataId.value = useRoutes?.query?.id || ''
  201. console.log( dataId.value, 'dataId.value')
  202. if (dataType === 1) {
  203. TreeAutoExpandKeys.value = getStoreValue('TreeExpandKeys')
  204. }
  205. formDataFormat({})
  206. queryById()
  207. formValue.value.shootingUser = userInfo.value['real_name']
  208. if (wbsNodeIds) {
  209. getFileTitleNamedata(wbsNodeIds)
  210. }
  211. })
  212. //详情
  213. const queryByLoading = ref(false)
  214. const queryById = async () => {
  215. if (dataId.value) {
  216. queryByLoading.value = true
  217. const { error, code, data } = await imageApi.queryById({ id: dataId.value })
  218. //判断状态
  219. queryByLoading.value = false
  220. if (!error && code === 200) {
  221. formDataFormat(getObjValue(data))
  222. }
  223. }
  224. }
  225. //获取题名
  226. const getFileTitleNamedata = async (wbsNodeIds) => {
  227. const { error, code, data } = await imageApi.getFileTitleName({ pKeyId: wbsNodeIds })
  228. //判断状态
  229. if (!error && code === 200) {
  230. let arr = Object.keys(data)
  231. if (arr.length > 0) {
  232. formValue.value.title = data
  233. } else {
  234. formValue.value.title = ''
  235. }
  236. }
  237. }
  238. //项目树被点击
  239. const wbsId = ref('')
  240. const treeItemInfo = ref({})
  241. const nodeWbsElTreeClick = ({ data, keys }) => {
  242. if (dataId.value.length > 1 && data['primaryKeyId'] !== wbsNodeIds) {
  243. window.$message.warning('编辑文件时,不可切换节点')
  244. return
  245. }
  246. if (data.notExsitChild === true) {
  247. treeItemInfo.value = data
  248. wbsId.value = data['primaryKeyId']
  249. if (dataId.value.length < 1) {
  250. formValue.value = {
  251. uploadTime: toDayDate,
  252. shootingTimeStr: toDayDate,
  253. shootingUser: userInfo.value['real_name'],
  254. filmCode: '',
  255. seeAlsoCode: '',
  256. }
  257. uploadFileList.value = []
  258. previewFileList.value = []
  259. }
  260. formValue.value.wbsId = data['primaryKeyId']
  261. getFileTitleNamedata(data['primaryKeyId'])
  262. //缓存自动展开
  263. TreeAutoExpandKeys.value = keys
  264. setStoreValue('TreeExpandKeys', keys)
  265. } else {
  266. wbsId.value = ''
  267. treeItemInfo.value = {}
  268. formValue.value.wbsId = null
  269. }
  270. }
  271. //表单相关数据
  272. const formRef = ref(null)
  273. const formValue = ref({
  274. uploadTime: toDayDate,
  275. shootingTimeStr: toDayDate,
  276. shootingUser: '',
  277. filmCode: '',
  278. seeAlsoCode: '',
  279. })
  280. const rules = {
  281. uploadTime: {
  282. required: true,
  283. trigger: 'blur',
  284. message: '请选择上传日期',
  285. },
  286. imageUrl: {
  287. required: true,
  288. message: '请先上传文件',
  289. },
  290. title: {
  291. required: true,
  292. trigger: 'blur',
  293. message: '请输入题名',
  294. },
  295. shootingUser: {
  296. required: true,
  297. trigger: 'blur',
  298. message: '请输入拍摄者',
  299. },
  300. shootingTimeStr: {
  301. required: true,
  302. trigger: 'blur',
  303. message: '请选择拍摄时间',
  304. },
  305. }
  306. //表单默认数据
  307. const formDataFormat = (info) => {
  308. //表单数据
  309. formValue.value = {
  310. uploadTime: toDayDate,
  311. shootingTimeStr: toDayDate,
  312. ...info,
  313. type: fileType || '2',
  314. wbsId: info?.wbsId || wbsNodeIds,
  315. classifyId: info?.classifyId || classifyId,
  316. projectId: info?.projectId || projectId.value,
  317. contractId: info?.contractId || contractId.value,
  318. }
  319. //原始文件地址
  320. let imageUrl = info['imageUrl'] || ''
  321. let imageUrlArr = imageUrl ? imageUrl.split(',') : []
  322. //PDF地址
  323. let pdfUrl = info['pdfUrl'] || ''
  324. let pdfUrlArr = pdfUrl ? pdfUrl.split(',') : []
  325. //处理数据
  326. if (imageUrlArr.length > 0) {
  327. //状态处理
  328. let InfoPdfUrl = pdfUrlArr.length === imageUrlArr.length
  329. //遍历数据
  330. for (let i = 0; i < imageUrlArr.length; i++) {
  331. let item = imageUrlArr[i]
  332. uploadFileList.value.push({
  333. name: getRandom(),
  334. url: item,
  335. page: '',
  336. pdfUrl: InfoPdfUrl ? pdfUrlArr[i] : '',
  337. })
  338. }
  339. } else {
  340. uploadFileList.value = []
  341. }
  342. }
  343. //上传组件参数
  344. const imageAccept = 'image/png,image/jpg,image/jpeg'
  345. const videoAccept = 'video/*'
  346. //上传文件的相关数据
  347. const previewFileList = ref([])
  348. const uploadFileList = ref([])
  349. //上传的文件结果
  350. const uploadsChange = ({ fileList }) => {
  351. uploadFileList.value = fileList
  352. }
  353. //上传进度
  354. const uploadsLoading = ref(false)
  355. const uploadsProgress = (val) => {
  356. uploadsLoading.value = val
  357. }
  358. //预览上传的文件
  359. const previewModal = ref(false)
  360. const previewVideoModal = ref(false)
  361. const initialIndex = ref(-1)
  362. const previewVideoUrl = ref('')
  363. const uploadsPreview = ({ index, fileArr }) => {
  364. if (fileType === 2) {
  365. previewFileList.value = fileArr
  366. initialIndex.value = index
  367. previewModal.value = true
  368. } else if (fileType === 1) {
  369. previewVideoUrl.value = fileArr[index]
  370. previewVideoModal.value = true
  371. }
  372. }
  373. //预览关闭
  374. const previewModalClose = () => {
  375. initialIndex.value = -1
  376. previewModal.value = false
  377. previewVideoModal.value = false
  378. }
  379. //删除上传的文件
  380. const uploadsDel = async ({ link }) => {
  381. const arrUrl = link.split('.com//')
  382. if (arrUrl.length > 0) {
  383. await ossApi.removeFile({ fileName: arrUrl[1] }, false)
  384. }
  385. }
  386. //上传记录表格
  387. const tableColumn = ref([
  388. { name: '上传日期', key: 'uploadTime' },
  389. { name: '题名', key: 'title' },
  390. { name: '拍摄者', key: 'shootingUser' },
  391. { name: '拍摄时间', key: 'shootingTimeStr' },
  392. ])
  393. const tableData = ref([])
  394. //保存
  395. const saveLoading = ref(false)
  396. const saveClick = () => {
  397. verifyFormData(false)
  398. }
  399. //保存并添加记录
  400. const saveLogClick = () => {
  401. verifyFormData(true)
  402. }
  403. //表单效验
  404. const shootingTimeStr = ref('')
  405. const verifyFormData = async (log) => {
  406. const formData = formValue.value
  407. const fileList = uploadFileList.value
  408. //处理文件
  409. let imageUrl = '', pdfUrl = ''
  410. if (fileList.length > 0) {
  411. imageUrl = arrToKey(fileList, 'url', ',')
  412. pdfUrl = arrToKey(fileList, 'pdfUrl', ',')
  413. }
  414. //设置数据
  415. formData.imageUrl = imageUrl
  416. formData.pdfUrl = pdfUrl
  417. shootingTimeStr.value = formData['shootingTimeStr'] || ''
  418. //验证数据
  419. if (!formData?.wbsId && dataType === 1) {
  420. window.$message?.warning('请先选择节点')
  421. } else {
  422. const res = await formValidate(formRef.value)
  423. if (res) {
  424. if (formData?.id) {
  425. updateImageclassifyFile(formData, log)
  426. } else {
  427. addImageclassifyFile(formData, log)
  428. }
  429. } else {
  430. window.$message?.warning('请先完善表单')
  431. }
  432. }
  433. }
  434. //新增资料
  435. const addImageclassifyFile = async (formData, log) => {
  436. saveLoading.value = true
  437. const { error, code } = await imageApi.addImageclassifyFile(formData)
  438. //判断状态
  439. saveLoading.value = false
  440. if (!error && code === 200) {
  441. window.$message?.success('保存成功')
  442. if (log) {
  443. tableData.value.push(deepClone(formValue.value))
  444. formDataFormat({})
  445. } else {
  446. toBackClick()
  447. }
  448. }
  449. }
  450. //修改资料
  451. const updateImageclassifyFile = async (formData, log) => {
  452. saveLoading.value = true
  453. const { error, code } = await imageApi.updateImageclassifyFile(formData)
  454. //判断状态
  455. saveLoading.value = false
  456. if (!error && code === 200) {
  457. window.$message?.success('保存成功')
  458. if (log) {
  459. tableData.value.push(deepClone(formValue.value))
  460. formDataFormat({})
  461. } else {
  462. toBackClick()
  463. }
  464. }
  465. }
  466. //处理data类型的自动展开
  467. const dataNodeExpandKeys = () => {
  468. let TimeStr = shootingTimeStr.value || ''
  469. let TimeArr = TimeStr.split('-')
  470. if (TimeStr && TimeArr.length > 0) {
  471. let timeKey = TimeArr[0] + '-' + TimeArr[1]
  472. setStoreValue('TreeExpandedKeys', [timeKey])
  473. }
  474. }
  475. //返回上页
  476. const toBackClick = () => {
  477. if (dataType === 1) {
  478. //NodeExpandKeys()
  479. } else if (dataType === 2) {
  480. dataNodeExpandKeys()
  481. }
  482. //返回上级
  483. router.push({
  484. path: '/other-file/image-view',
  485. query: {
  486. fileType: fileType,
  487. type: dataType,
  488. id: classifyId,
  489. },
  490. })
  491. }
  492. //左右拖动,改变树形结构宽度
  493. const leftWidth = ref(382)
  494. const onmousedown = () => {
  495. const leftNum = isCollapse.value ? 142 : 272
  496. document.onmousemove = (ve) => {
  497. let diffVal = ve.clientX - leftNum
  498. if (diffVal >= 310 && diffVal <= 900) {
  499. leftWidth.value = diffVal
  500. }
  501. }
  502. document.onmouseup = () => {
  503. document.onmousemove = null
  504. document.onmouseup = null
  505. }
  506. }
  507. </script>
  508. <style lang="scss" scoped>
  509. @import '../../styles/other-file/image-form.scss';
  510. </style>
  511. <style lang="scss">
  512. .hc-form-row-box {
  513. height: 100%;
  514. .el-col {
  515. height: 100%;
  516. .el-date-editor {
  517. --el-date-editor-width: 100%;
  518. .el-input__wrapper {
  519. width: 100%;
  520. }
  521. }
  522. .el-alert {
  523. margin-top: 14px;
  524. --el-alert-padding: 0px 16px;
  525. }
  526. }
  527. }
  528. .preview-video {
  529. width: 100%;
  530. }
  531. </style>