MaterialMange.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. <!--
  2. * @Author: 半生瓜 1515706227@qq.com
  3. * @Date: 2024-05-06 19:31:40
  4. * @LastEditors: 半生瓜 1515706227@qq.com
  5. * @LastEditTime: 2024-05-28 00:03:36
  6. * @FilePath: \vue-element-plus-admin-mini\src\views\zy\Menu12.vue
  7. * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  8. -->
  9. <script setup lang="tsx">
  10. import { ElInput, ElSelect, ElOption } from 'element-plus'
  11. import { ref } from 'vue'
  12. import { Dialog } from '@/components/Dialog'
  13. import { ContentWrap } from '@/components/ContentWrap'
  14. import { useI18n } from '@/hooks/web/useI18n'
  15. import { Table, TableColumn, TableSlotDefault } from '@/components/Table'
  16. import { upTemplate, saveTemplate } from '@/api/table'
  17. import { saveResource, getMaterial, deleteResource, batchsavecz } from '@/api/material'
  18. import { reactive, unref } from 'vue'
  19. import { ElButton, ElMessageBox, ElMessage, ElIcon } from 'element-plus'
  20. import { useTable } from '@/hooks/web/useTable'
  21. import { Search, Edit, Delete } from '@element-plus/icons-vue'
  22. import { useValidator } from '@/hooks/web/useValidator'
  23. import { Form, FormSchema } from '@/components/Form'
  24. import { useForm } from '@/hooks/web/useForm'
  25. import { BaseButton } from '@/components/Button'
  26. import { useUserStore } from '@/store/modules/user'
  27. import { log } from 'console'
  28. import { json } from 'stream/consumers'
  29. const PATH_URL = window.VITE_API_BASE_PATH
  30. const tietu = ref('')
  31. const { required } = useValidator()
  32. const text = ref('')
  33. const materialType = ref('')
  34. const userStore = useUserStore()
  35. defineOptions({
  36. name: 'TemplateManage'
  37. })
  38. const { tableRegister, tableState, tableMethods } = useTable({
  39. fetchDataApi: async () => {
  40. const { currentPage, pageSize } = tableState
  41. const res = await getMaterial({
  42. page: unref(currentPage),
  43. pageSize: unref(pageSize),
  44. name: unref(text),
  45. materialType: unref(materialType)
  46. })
  47. res.data.content.map((item) => {
  48. item.materialIcon = PATH_URL + item.materialIcon
  49. item.icon = item.materialIcon
  50. })
  51. console.log('kankan2232', res.data.content)
  52. return {
  53. list: res.data.content,
  54. total: res.data.totalElements
  55. }
  56. }
  57. })
  58. const { loading, dataList, total, currentPage, pageSize } = tableState
  59. const { refresh, getElTableExpose } = tableMethods
  60. const { t } = useI18n()
  61. const columns = reactive<TableColumn[]>([
  62. {
  63. field: 'selection',
  64. type: 'selection'
  65. },
  66. {
  67. field: 'index',
  68. label: t('tableDemo.index'),
  69. type: 'index'
  70. },
  71. {
  72. field: 'materialName',
  73. label: '材质名称'
  74. },
  75. {
  76. field: 'materialType',
  77. label: '材质类型',
  78. formatter: (_: Recordable, __: TableColumn, cellValue: number) => {
  79. return cellValue === 1 ? '贴图' : cellValue === 2 ? '颜色' : ''
  80. }
  81. },
  82. {
  83. field: 'icon',
  84. label: '图标'
  85. },
  86. {
  87. field: 'action',
  88. label: t('tableDemo.action'),
  89. slots: {
  90. default: (data) => {
  91. return (
  92. <>
  93. <ElButton type="primary" onClick={() => edittab(data)}>
  94. {t('tableDemo.edit')}
  95. </ElButton>
  96. <ElButton type="danger" onClick={() => deletetab(data)}>
  97. {t('tableDemo.delete')}
  98. </ElButton>
  99. </>
  100. )
  101. }
  102. }
  103. }
  104. ])
  105. const imageUrl = ref('')
  106. const imageUrl2 = ref('')
  107. const isedit = ref('添加')
  108. //删除
  109. const deletetab = async (data: TableSlotDefault) => {
  110. ElMessageBox.confirm('确定删除该数据?')
  111. .then(async () => {
  112. let arr = {
  113. materialIds: data.row.materialId
  114. }
  115. const res = await deleteResource(arr)
  116. refresh()
  117. refresh()
  118. if (res.code == 200) {
  119. ElMessage.success('删除成功')
  120. }
  121. refresh()
  122. })
  123. .catch(() => {
  124. // catch error
  125. })
  126. }
  127. const dialogVisible = ref(false)
  128. const dialogVisible2 = ref(false)
  129. const token = userStore.getToken
  130. const Authorization = `Bearer ${token}`
  131. const headers = ref({ Authorization: Authorization })
  132. const { formRegister, formMethods } = useForm()
  133. const { getElFormExpose, getFormData } = formMethods
  134. const schema = reactive<FormSchema[]>([
  135. {
  136. field: 'materialType',
  137. label: '材质类型',
  138. component: 'Select',
  139. colProps: {
  140. span: 24
  141. },
  142. componentProps: {
  143. options: [
  144. { label: '贴图', value: 1 },
  145. { label: '颜色', value: 2 }
  146. ],
  147. placeholder: '请选择材质类型',
  148. onChange: (value) => {
  149. if (value === 2) {
  150. schema.find((item) => item.field === 'TIETU').colProps.span = 0
  151. } else {
  152. schema.find((item) => item.field === 'TIETU').colProps.span = 24
  153. }
  154. }
  155. },
  156. formItemProps: {
  157. rules: [required()]
  158. }
  159. },
  160. {
  161. field: 'materialName',
  162. label: '材质名称',
  163. component: 'Input',
  164. colProps: {
  165. span: 24
  166. },
  167. componentProps: {
  168. style: {
  169. width: '100%'
  170. },
  171. placeholder: '请输入材质名称'
  172. },
  173. formItemProps: {
  174. rules: [required()]
  175. }
  176. },
  177. {
  178. field: 'materialIcon',
  179. component: 'Upload',
  180. colProps: {
  181. span: 24
  182. },
  183. label: '图标',
  184. formItemProps: {
  185. rules: [required()]
  186. },
  187. componentProps: {
  188. action: PATH_URL + '/resource/manage/uploadImg',
  189. headers: headers,
  190. showFileList: false,
  191. onSuccess: async (_response, uploadFile) => {
  192. imageUrl.value = URL.createObjectURL(uploadFile.raw!)
  193. const formData = await getFormData()
  194. formData.materialIcon = _response.data
  195. },
  196. beforeUpload: (rawFile) => {
  197. console.log('sadghasgdaj', rawFile.name.includes('jpeg'))
  198. console.log('kankangeshi', rawFile)
  199. if (rawFile.name.includes('jpeg')) {
  200. ElMessage.error('上传格式:png、jpg!')
  201. return false
  202. }
  203. if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpeg') {
  204. ElMessage.error('上传格式:png、jpg!')
  205. return false
  206. }
  207. return true
  208. },
  209. slots: {
  210. default: () => (
  211. <>
  212. {imageUrl.value ? <img src={imageUrl.value} class="avatar" /> : null}
  213. {!imageUrl.value ? (
  214. <ElIcon class="avatar-uploader-icon" size="large" style="font-size: 50px">
  215. +
  216. </ElIcon>
  217. ) : null}
  218. </>
  219. ),
  220. tip: () => <div class="el-upload__tip">上传格式:png、jpg,大小:56x56px;</div>
  221. }
  222. }
  223. },
  224. {
  225. field: 'TIETU',
  226. component: 'Upload',
  227. colProps: {
  228. span: 24
  229. },
  230. label: '贴图图片',
  231. formItemProps: {},
  232. componentProps: {
  233. action: PATH_URL + '/resource/manage/uploadImg',
  234. headers: headers,
  235. showFileList: false,
  236. onSuccess: async (_response, uploadFile) => {
  237. imageUrl2.value = URL.createObjectURL(uploadFile.raw!)
  238. const formData = await getFormData()
  239. formData.TIETU = _response.data
  240. console.log('asdhjasdkj', formData)
  241. },
  242. beforeUpload: (rawFile) => {
  243. console.log('sadghasgdaj', rawFile.name.includes('jpeg'))
  244. console.log('kankangeshi', rawFile)
  245. if (rawFile.name.includes('jpeg')) {
  246. ElMessage.error('上传格式:png、jpg!')
  247. return false
  248. }
  249. if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpeg') {
  250. ElMessage.error('上传格式:png、jpg!')
  251. return false
  252. }
  253. return true
  254. },
  255. slots: {
  256. default: () => (
  257. <>
  258. {imageUrl2.value ? <img src={imageUrl2.value} class="avatar" /> : null}
  259. {!imageUrl2.value ? (
  260. <ElIcon class="avatar-uploader-icon" size="large" style="font-size: 50px">
  261. +
  262. </ElIcon>
  263. ) : null}
  264. </>
  265. ),
  266. tip: () => <div class="el-upload__tip">上传格式:png、jpg,大小:56x56px;</div>
  267. }
  268. }
  269. },
  270. {
  271. field: 'jsonValue',
  272. label: '材质内容',
  273. component: 'Input',
  274. colProps: {
  275. span: 24
  276. },
  277. componentProps: {
  278. type: 'textarea',
  279. rows: 4,
  280. placeholder: '请输入材质内容'
  281. },
  282. formItemProps: {
  283. rules: [required()]
  284. }
  285. }
  286. ])
  287. const schema2 = reactive<FormSchema[]>([
  288. {
  289. field: 'jsonPath',
  290. component: 'Upload',
  291. label: '材质内容',
  292. colProps: {
  293. span: 24
  294. },
  295. componentProps: {
  296. limit: 1,
  297. action: PATH_URL + '/resource/manage/addModelCompress',
  298. headers: headers,
  299. fileList: [],
  300. multiple: true,
  301. onPreview: (uploadFile) => {
  302. console.log(uploadFile)
  303. },
  304. onRemove: async (file) => {
  305. const formData = await getFormData()
  306. formData.jsonPath = ''
  307. formData.compressFileName = ''
  308. formData.uploadCompress = false
  309. },
  310. onSuccess: async (_response, uploadFile) => {
  311. console.log('kankan_response', uploadFile)
  312. const formData = await getFormData()
  313. formData.compressFilePath = _response.data
  314. },
  315. beforeRemove: (uploadFile) => {},
  316. onExceed: (files, uploadFiles) => {
  317. ElMessage.warning('只能上传一个资源,请移除后重新上传')
  318. },
  319. beforeUpload: (rawFile) => {
  320. if (rawFile.type !== 'application/x-zip-compressed' && rawFile.name.indexOf('.rar') == -1) {
  321. ElMessage.error('只能上传RAR、ZIP文件')
  322. return false
  323. }
  324. return true
  325. },
  326. slots: {
  327. default: () => <BaseButton type="primary">点击上传</BaseButton>,
  328. tip: () => <div class="el-upload__tip">文件类型:RAR\ZIP</div>
  329. }
  330. }
  331. }
  332. ])
  333. //编辑
  334. const edittab = async (data: TableSlotDefault) => {
  335. console.log('shanchu', data)
  336. isedit.value = '编辑'
  337. dialogVisible.value = true
  338. const formRef = await getElFormExpose()
  339. const formData = await getFormData()
  340. formData.compressFileName = data.row.compressFileName
  341. formData.jsonPath = data.row.jsonPath
  342. formData.TIETU = data.row.jsonValue.texture
  343. formData.materialName = data.row.materialName
  344. let a = JSON.parse(JSON.stringify(data.row.jsonValue))
  345. tietu.value = a.texture
  346. imageUrl2.value = PATH_URL + data.row.jsonValue.texture
  347. delete a.texture
  348. formData.jsonValue = JSON.stringify(a)
  349. formData.materialType = data.row.materialType
  350. formData.materialIcon = data.row.materialIcon.replace(PATH_URL, '')
  351. imageUrl.value = data.row.materialIcon
  352. formData.materialId = data.row.materialId
  353. schema[1].componentProps.fileList = [
  354. {
  355. name: data.row.compressFileName,
  356. url: data.row.jsonPath
  357. }
  358. ]
  359. // 如果材质类型是颜色,不显示贴图图标
  360. if (formData.materialType === 2) {
  361. schema.find((item) => item.field === 'TIETU').colProps.span = 0
  362. } else {
  363. schema.find((item) => item.field === 'TIETU').colProps.span = 24
  364. }
  365. }
  366. // 添加编辑模板管理
  367. const signIn = async () => {
  368. const formRef = await getElFormExpose()
  369. const formData = await getFormData()
  370. console.log('asdhajgsh', formData.jsonValue)
  371. if (!formData.TIETU && formData.materialType == 1) {
  372. ElMessage.warning('请上传贴图图标')
  373. return
  374. }
  375. try {
  376. formData.jsonValue = JSON.parse(formData.jsonValue)
  377. } catch (error) {
  378. ElMessage.error('材质内容格式错误')
  379. return
  380. }
  381. console.log('shdjasd1', formData.TIETU)
  382. if (formData.TIETU) {
  383. formData.jsonValue.texture = formData.TIETU
  384. } else {
  385. formData.jsonValue.texture = tietu.value
  386. }
  387. //如果是编辑去掉icon的拼接
  388. console.log('kakkkkak', formData)
  389. await formRef?.validate(async (isValid) => {
  390. if (isValid) {
  391. const res = await saveResource(formData)
  392. console.log('shdjasd22', res)
  393. if (res) {
  394. dialogVisible.value = false
  395. ElMessage.success('保存成功')
  396. refresh()
  397. } else {
  398. console.log('asdhjasd')
  399. delete formData.jsonValue.texture
  400. formData.jsonValue = JSON.stringify(formData.jsonValue)
  401. }
  402. }
  403. })
  404. }
  405. // 批量添加材质
  406. const signIn2 = async () => {
  407. const formRef = await getElFormExpose()
  408. const formData = await getFormData()
  409. //如果是编辑去掉icon的拼接
  410. console.log('kakkkkak', formData)
  411. await formRef?.validate(async (isValid) => {
  412. if (isValid) {
  413. const res = await batchsavecz(formData)
  414. if (res) {
  415. dialogVisible2.value = false
  416. refresh()
  417. }
  418. }
  419. })
  420. }
  421. //多选删除
  422. const getSelections = async () => {
  423. const elTableRef = await getElTableExpose()
  424. const selections = elTableRef?.getSelectionRows()
  425. let arr = {
  426. materialIds: []
  427. }
  428. if (selections) {
  429. arr.materialIds = selections.map((item) => {
  430. return item.materialId
  431. })
  432. }
  433. if (arr.materialIds.length !== 0) {
  434. ElMessageBox.confirm('确定删除所选数据?')
  435. .then(async () => {
  436. console.log('kankan', arr)
  437. const res = await deleteResource(arr)
  438. console.log('kkkkkkss', res)
  439. if (res.code == 200) {
  440. ElMessage.success('删除成功')
  441. }
  442. refresh()
  443. })
  444. .catch(() => {
  445. // catch error
  446. })
  447. } else {
  448. ElMessage.warning('请选择数据')
  449. }
  450. }
  451. const options = [
  452. {
  453. value: 1,
  454. label: '贴图'
  455. },
  456. {
  457. value: 2,
  458. label: '颜色'
  459. }
  460. ]
  461. //搜索
  462. const handersearch = function () {
  463. tableState.currentPage.value = 1
  464. refresh()
  465. }
  466. const tianjia = async () => {
  467. imageUrl.value = ''
  468. imageUrl2.value = ''
  469. isedit.value = '添加'
  470. schema[1].componentProps.fileList = []
  471. dialogVisible.value = true
  472. }
  473. </script>
  474. <template>
  475. <ContentWrap>
  476. <div style="margin-bottom: 10px">
  477. <span style="color: #606266"> 材质名称:</span>
  478. <el-input
  479. v-model="text"
  480. style="width: 200px; height: 43px; margin: 7px"
  481. placeholder="请输入材质名称"
  482. />
  483. <span style="color: #606266"> 材质状态:</span>
  484. <el-select
  485. v-model="materialType"
  486. clearable
  487. placeholder="全部"
  488. size="large"
  489. style="width: 240px"
  490. >
  491. <el-option
  492. v-for="item in options"
  493. :key="item.value"
  494. :label="item.label"
  495. :value="item.value"
  496. />
  497. </el-select>
  498. <ElButton
  499. style="margin-left: 20px"
  500. type="primary"
  501. size="large"
  502. @click="handersearch"
  503. :icon="Search"
  504. >搜索</ElButton
  505. >
  506. <ElButton type="success" size="large" @click="tianjia" :icon="Edit">添加</ElButton>
  507. <ElButton type="danger" size="large" @click="getSelections" :icon="Delete">删除</ElButton>
  508. </div>
  509. <Table
  510. v-model:pageSize="pageSize"
  511. v-model:currentPage="currentPage"
  512. :columns="columns"
  513. :image-preview="['icon']"
  514. :data="dataList"
  515. row-key="id"
  516. headerAlign="center"
  517. align="center"
  518. :loading="loading"
  519. sortable
  520. :pagination="{
  521. total: total
  522. }"
  523. @register="tableRegister"
  524. @refresh="refresh"
  525. />
  526. </ContentWrap>
  527. <Dialog v-model="dialogVisible" maxHeight="580px" width="35rem" :title="isedit">
  528. <Form :schema="schema" @register="formRegister" />
  529. <template #footer>
  530. <div style="width: 100%; display: flex; justify-content: center">
  531. <BaseButton
  532. style="font-size: 1rem; height: 2.2rem; margin: auto"
  533. type="primary"
  534. class="w-[15%]"
  535. @click="signIn"
  536. >
  537. 确定
  538. </BaseButton>
  539. </div>
  540. </template>
  541. </Dialog>
  542. <Dialog v-model="dialogVisible2" maxHeight="390px" width="35rem" :title="isedit">
  543. <Form :schema="schema2" @register="formRegister" />
  544. <template #footer>
  545. <div style="width: 100%; display: flex; justify-content: center">
  546. <BaseButton
  547. style="font-size: 1rem; height: 2.2rem; margin: auto"
  548. type="primary"
  549. class="w-[15%]"
  550. @click="signIn2"
  551. >
  552. 确定
  553. </BaseButton>
  554. </div>
  555. </template>
  556. </Dialog>
  557. </template>
  558. <style>
  559. .el-image__preview {
  560. width: 56px !important;
  561. height: 56px !important;
  562. }
  563. </style>
  564. <style lang="less">
  565. .el-upload {
  566. position: relative;
  567. overflow: hidden;
  568. cursor: pointer;
  569. border: 1px dashed var(--el-border-color);
  570. border-radius: 6px;
  571. transition: var(--el-transition-duration-fast);
  572. }
  573. .el-upload:hover {
  574. border-color: var(--el-color-primary);
  575. }
  576. .el-icon.avatar-uploader-icon {
  577. width: 120px;
  578. height: 120px;
  579. font-size: 28px;
  580. color: #8c939d;
  581. text-align: center;
  582. }
  583. .avatar {
  584. width: 120px;
  585. height: 120px;
  586. }
  587. </style>