template.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. <template>
  2. <hc-drawer v-model="isShow" to-id="hc-main-box" is-close @close="drawerClose">
  3. <hc-body split>
  4. <template #left>
  5. <hc-card>
  6. <template #header>
  7. <hc-search-input v-model="searchTreeName" placeholder="请输入关键字" @search="searchTreeNameClick" />
  8. </template>
  9. <template v-if="isTreeMode === 1">
  10. <hc-lazy-tree
  11. v-if="isShow" :root-menu="treeMenuRoot" is-load-menu :h-props="treeProps" tree-key="id"
  12. @load-menu="treeLazyMenu" @load="treeLoadNode" @node-tap="treeNodeTap" @menu-tap="treeMenuClick"
  13. >
  14. <template #name="{ data }">
  15. <span class="text-16px font-400">{{ data.name }}</span>
  16. </template>
  17. </hc-lazy-tree>
  18. </template>
  19. <template v-if="isTreeMode === 2">
  20. <hc-data-tree
  21. ref="treeRef" :root-menu="treeMenuRoot" is-load-menu :h-props="treeProps" tree-key="id" :datas="treeData"
  22. @load-menu="treeDataMenu" @node-tap="treeNodeTap" @menu-tap="treeMenuClick"
  23. >
  24. <template #name="{ data }">
  25. <span class="text-16px font-400">{{ data.name }}</span>
  26. </template>
  27. </hc-data-tree>
  28. </template>
  29. </hc-card>
  30. </template>
  31. <hc-card>
  32. <template #header>
  33. <template v-if="isCheckd">
  34. <template v-if="tableTempExcelProps.file">
  35. <div class="table-temp-name truncate">
  36. <span>{{ tableTempExcelProps.title }}</span>
  37. <i class="i-iconoir-check-circle-solid" />
  38. </div>
  39. <el-upload
  40. ref="file1Ref" :auto-upload="false" :show-file-list="false" action="#"
  41. :limit="1" :file-list="fileList" accept=".xls,.xlsx" :on-change="uploadChange"
  42. >
  43. <el-button hc-btn type="primary">重新上传</el-button>
  44. </el-upload>
  45. <el-button class="ml-2" hc-btn type="danger" @click="delectExcelMS">删除</el-button>
  46. <el-button hc-btn type="success" @click="downloadExcel">下载Excel</el-button>
  47. </template>
  48. <template v-else>
  49. <el-upload
  50. ref="file2Ref" :auto-upload="false" :show-file-list="false" action="#" :limit="1"
  51. :file-list="fileList" accept=".xls,.xlsx" :on-change="uploadChange"
  52. >
  53. <el-button hc-btn type="primary">上传Excel</el-button>
  54. </el-upload>
  55. </template>
  56. <template v-if="excelInfo.templateExtension">
  57. <div class="table-temp-name truncate">
  58. <span>{{ excelInfo.templateExtension }}</span>
  59. <i class="i-iconoir-check-circle-solid" />
  60. </div>
  61. <el-button hc-btn type="danger" @click="delectExcelMSModel">删除</el-button>
  62. <el-button hc-btn type="success" @click="downloadExcelModel">下载模板</el-button>
  63. </template>
  64. </template>
  65. <template v-else>
  66. <div class="text-red">该目录为根目录没有EXCEL文件</div>
  67. </template>
  68. </template>
  69. <template #extra>
  70. <el-button v-if="tableTempExcelProps.file" hc-btn type="primary" @click="fullScreenClick">全屏显示</el-button>
  71. </template>
  72. <div :id="tableTempExcelId" class="relative h-full">
  73. <hc-online-office v-if="isShow" ui="hc-table-temp-excel" :props="tableTempExcelProps" />
  74. </div>
  75. </hc-card>
  76. </hc-body>
  77. <!-- 新增清表 -->
  78. <HcAddExcel v-model="addExcelShow" :info="addExcelInfo" :type="addExcelType" @finish="pseudoRefresh" />
  79. <!-- 调整排序 -->
  80. <HcTreeSort v-model="treeSortShow" :data="treeSortData" @finish="pseudoRefresh" />
  81. <!-- 上传Excel表格 -->
  82. <HcExcelUpload v-model="excelUploadShow" :data="excelUploadData" @finish="pseudoRefresh" />
  83. </hc-drawer>
  84. </template>
  85. <script setup>
  86. import { ref, watch } from 'vue'
  87. import { useAppStore } from '~src/store'
  88. import screenfull from 'screenfull'
  89. import { HcDelMsg } from 'hc-vue3-ui'
  90. import { ElLoading } from 'element-plus'
  91. import { getArrValue, getObjValue, getRandom, isNullES, newDownBlob } from 'js-fast-way'
  92. import HcAddExcel from './add-excel.vue'
  93. import HcTreeSort from './tree-sort.vue'
  94. import HcExcelUpload from './excel-upload.vue'
  95. import mainApi from '~api/exctab/exceltab'
  96. const props = defineProps({
  97. data: {
  98. type: Object,
  99. default: () => ({}),
  100. },
  101. })
  102. //事件
  103. const emit = defineEmits(['close'])
  104. const store = useAppStore()
  105. const userInfo = ref(store.getUserInfo)
  106. //双向绑定
  107. const isShow = defineModel('modelValue', {
  108. default: false,
  109. })
  110. //监听数据
  111. const dataInfo = ref(props.data)
  112. watch(() => props.data, (data) => {
  113. dataInfo.value = data
  114. }, { immediate: true, deep: true })
  115. //监听显示
  116. watch(isShow, (val) => {
  117. if (val) getDataApi()
  118. })
  119. //处理相关数据
  120. const tableTempExcelId = ref('')
  121. const getDataApi = () => {
  122. tableTempExcelId.value = getRandom(6)
  123. }
  124. //树搜索
  125. const isTreeMode = ref(1) //1懒加载,2全加载
  126. const searchTreeName = ref('')
  127. const searchTreeNameClick = async () => {
  128. if (isNullES(searchTreeName.value)) {
  129. isTreeMode.value = 1
  130. } else {
  131. isTreeMode.value = 2
  132. await getTreeAllData()
  133. treeRef.value?.treeRef?.filter(searchTreeName.value)
  134. }
  135. }
  136. //树配置
  137. const treeRef = ref(null)
  138. const treeProps = {
  139. label: 'name',
  140. children: 'children',
  141. isLeaf: (item) => {
  142. return !item.hasChildren
  143. },
  144. }
  145. //树菜单根节点
  146. const treeMenuRoot = [
  147. { icon: 'add-circle', label: '新增', key: 'add' },
  148. { icon: 'delete-bin', label: '删除', key: 'del' },
  149. ]
  150. //懒加载树的菜单
  151. const treeLazyMenu = ({ item, level }, resolve) => {
  152. let newMenu = []
  153. if (item.fileType !== 3) {
  154. newMenu.push({ icon: 'add-circle', label: '新增', key: 'add' })
  155. }
  156. if (item.fileType !== 1) {
  157. newMenu.push({ icon: 'draft', label: '编辑', key: 'edit' })
  158. }
  159. if (level !== 1) {
  160. newMenu.push({ icon: 'sort-asc', label: '排序', key: 'sort' })
  161. }
  162. if (item.fileType !== 3) {
  163. newMenu.push({ icon: 'file-upload', label: '上传', key: 'upload' })
  164. }
  165. newMenu.push({ icon: 'delete-bin', label: '删除', key: 'del' })
  166. resolve(newMenu)
  167. }
  168. //全加载树的菜单
  169. const treeDataMenu = ({ node, item, level }, resolve) => {
  170. const { isLeaf } = node
  171. let newMenu = []
  172. if (item.fileType !== 3) {
  173. newMenu.push({ icon: 'add-circle', label: '新增', key: 'add' })
  174. }
  175. if (item.fileType !== 1) {
  176. newMenu.push({ icon: 'draft', label: '编辑', key: 'edit' })
  177. }
  178. if (isLeaf) {
  179. newMenu.push({ icon: 'sort-asc', label: '排序', key: 'sort' })
  180. }
  181. if (level !== 1) {
  182. newMenu.push({ icon: 'file-upload', label: '上传', key: 'upload' })
  183. }
  184. newMenu.push({ icon: 'delete-bin', label: '删除', key: 'del' })
  185. resolve(newMenu)
  186. }
  187. //菜单被点击
  188. const treeMenuClick = ({ key, data, node }) => {
  189. console.log(key)
  190. if (key === 'add') {
  191. addExcelInfo.value = getObjValue(data)
  192. addExcelType.value = '新增'
  193. addExcelShow.value = true
  194. } else if (key === 'edit') {
  195. addExcelInfo.value = getObjValue(data)
  196. addExcelType.value = '编辑'
  197. addExcelShow.value = true
  198. } else if (key === 'sort') {
  199. treeSortData.value = {
  200. parentId: node?.parent?.data?.id ?? '',
  201. modeId: dataInfo.value.id,
  202. }
  203. treeSortShow.value = true
  204. } else if (key === 'upload') {
  205. excelUploadData.value = data
  206. excelUploadShow.value = true
  207. console.log(data)
  208. } else if (key === 'del') {
  209. if (data.hasChildren) {
  210. window.$message.warning('该节点下有子节点,无法删除')
  211. return false
  212. }
  213. HcDelMsg(async (resolve) => {
  214. const { code } = await mainApi.del(data.id)
  215. resolve() //关闭弹窗的回调
  216. if (code === 200) {
  217. window.$message.success('删除成功')
  218. pseudoRefresh()
  219. }
  220. })
  221. }
  222. }
  223. //新增/编辑清表
  224. const addExcelShow = ref(false)
  225. const addExcelInfo = ref({})
  226. const addExcelType = ref('')
  227. //调整排序
  228. const treeSortShow = ref(false)
  229. const treeSortData = ref({})
  230. //上传文件
  231. const excelUploadShow = ref(false)
  232. const excelUploadData = ref({})
  233. //伪刷新
  234. const pseudoRefresh = () => {
  235. const val = isTreeMode.value
  236. isTreeMode.value = 4
  237. tableTempExcelProps.value = {}
  238. setTimeout(()=> {
  239. isTreeMode.value = val
  240. }, 500)
  241. }
  242. //全加载树
  243. const treeData = ref([])
  244. const getTreeAllData = async () => {
  245. const { data } = await mainApi.tabLazyTreeAll({
  246. modeId: dataInfo.value.id,
  247. //name: searchTreeName.value,
  248. name: '',
  249. })
  250. treeData.value = getArrValue(data)
  251. }
  252. //懒加载树
  253. const treeLoadNode = async ({ item, level }, resolve) => {
  254. const parentId = level === 0 ? 0 : item.id
  255. const { data } = await mainApi.tabLazyTree({
  256. parentId: parentId,
  257. modeId: dataInfo.value.id,
  258. })
  259. resolve(getArrValue(data))
  260. }
  261. //在线编辑表格文件的配置
  262. const tableTempExcelProps = ref({})
  263. //树节点被点击
  264. const nodeInfo = ref({})
  265. const isCheckd = ref(false)
  266. const treeNodeTap = ({ data }) => {
  267. nodeInfo.value = data
  268. isCheckd.value = !data.hasChildren || data.fileType === 3
  269. if (isCheckd.value) {
  270. getDetailExcel(data.id)
  271. } else {
  272. tableTempExcelProps.value = {}
  273. }
  274. }
  275. //获取模板详情
  276. const excelInfo = ref({})
  277. const getDetailExcel = async (dataId) => {
  278. const { code, data } = await mainApi.detailExcel(dataId)
  279. if (code !== 200) return
  280. const { id, extension, fileUrl } = getObjValue(data)
  281. const { user_id, user_name } = userInfo.value
  282. excelInfo.value = getObjValue(data)
  283. tableTempExcelProps.value = {
  284. type: 'xlsx',
  285. key: id + '_' + Math.random() + '',
  286. title: extension,
  287. file: fileUrl,
  288. userId: user_id,
  289. userName: user_name,
  290. }
  291. }
  292. //上传
  293. const file1Ref = ref(null)
  294. const file2Ref = ref(null)
  295. const fileList = ref([])
  296. //文件选择
  297. const uploadChange = async (file) => {
  298. const loading = ElLoading.service({
  299. text: '上传文件中...',
  300. })
  301. const form = excelInfo.value
  302. fileList.value = [file.raw]
  303. let formData = new FormData()
  304. formData.append('file', ...fileList.value)
  305. formData.append('nodeId', form.id)
  306. const temp = tableTempExcelProps.value
  307. if (temp.file && temp.file.length >= 2) {
  308. formData.append('type', 2)
  309. } else {
  310. formData.append('type', 1)
  311. }
  312. const { code } = await mainApi.uploadExcel(formData)
  313. loading.close()
  314. if (code === 200) {
  315. window.$message.success('保存成功')
  316. pseudoRefresh()
  317. }
  318. if (file1Ref.value) {
  319. file1Ref.value?.clearFiles()
  320. }
  321. if (file2Ref.value) {
  322. file2Ref.value?.clearFiles()
  323. }
  324. }
  325. //删除
  326. const delectExcelMS = () => {
  327. HcDelMsg(async (resolve) => {
  328. const form = excelInfo.value
  329. const { code } = await mainApi.deleteExcel({
  330. id: form.id,
  331. fileUrl: '',
  332. })
  333. resolve() //关闭弹窗的回调
  334. if (code === 200) {
  335. window.$message.success('删除成功')
  336. pseudoRefresh()
  337. }
  338. })
  339. }
  340. //下载Excel
  341. const downloadExcel = async () => {
  342. const form = excelInfo.value
  343. const { val } = await mainApi.downExcelFile(form.id)
  344. newDownBlob(val).then()
  345. }
  346. //删除
  347. const delectExcelMSModel = () => {
  348. HcDelMsg(async (resolve) => {
  349. const form = excelInfo.value
  350. const { code } = await mainApi.deleteExcelModel({
  351. id: form.id,
  352. fileUrl: '',
  353. })
  354. resolve() //关闭弹窗的回调
  355. if (code === 200) {
  356. window.$message.success('删除成功')
  357. pseudoRefresh()
  358. }
  359. })
  360. }
  361. //下载模板
  362. const downloadExcelModel = async () => {
  363. const form = excelInfo.value
  364. const { val } = await mainApi.downExcelFileModel(form.id)
  365. newDownBlob(val).then()
  366. }
  367. //全屏显示
  368. const fullScreenClick = () => {
  369. // 判断是否支持
  370. if (!screenfull.isEnabled) {
  371. window.$message.warning('当前浏览器不支持全屏')
  372. return false
  373. }
  374. //指定全屏区域元素
  375. const element = document.getElementById(tableTempExcelId.value)
  376. if (element) screenfull.request(element)
  377. }
  378. //关闭抽屉
  379. const drawerClose = () => {
  380. isShow.value = false
  381. tableTempExcelProps.value = {}
  382. dataInfo.value = {}
  383. emit('close')
  384. }
  385. </script>
  386. <style scoped lang="scss">
  387. .table-temp-name {
  388. position: relative;
  389. box-sizing: border-box;
  390. min-width: 200px;
  391. height: 28px;
  392. border: 1px solid gainsboro;
  393. padding: 0 10px;
  394. border-radius: 3px;
  395. display: flex;
  396. justify-content: space-between;
  397. align-items: center;
  398. margin-right: 10px;
  399. font-size: 14px;
  400. i {
  401. color: #00a870;
  402. margin-left: 10px;
  403. }
  404. }
  405. .hc-table-temp-excel {
  406. position: relative;
  407. }
  408. </style>