MaterialMange.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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('kankangeshi', rawFile)
  198. if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpeg') {
  199. ElMessage.error('上传格式:png、jpg!')
  200. return false
  201. }
  202. return true
  203. },
  204. slots: {
  205. default: () => (
  206. <>
  207. {imageUrl.value ? <img src={imageUrl.value} class="avatar" /> : null}
  208. {!imageUrl.value ? (
  209. <ElIcon class="avatar-uploader-icon" size="large" style="font-size: 50px">
  210. +
  211. </ElIcon>
  212. ) : null}
  213. </>
  214. ),
  215. tip: () => <div class="el-upload__tip">上传格式:png、jpg,大小:56x56px;</div>
  216. }
  217. }
  218. },
  219. {
  220. field: 'TIETU',
  221. component: 'Upload',
  222. colProps: {
  223. span: 24
  224. },
  225. label: '贴图图片',
  226. formItemProps: {},
  227. componentProps: {
  228. action: PATH_URL + '/resource/manage/uploadImg',
  229. headers: headers,
  230. showFileList: false,
  231. onSuccess: async (_response, uploadFile) => {
  232. imageUrl2.value = URL.createObjectURL(uploadFile.raw!)
  233. const formData = await getFormData()
  234. formData.TIETU = _response.data
  235. console.log('asdhjasdkj', formData)
  236. },
  237. beforeUpload: (rawFile) => {
  238. console.log('kankangeshi', rawFile)
  239. if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpeg') {
  240. ElMessage.error('上传格式:png、jpg!')
  241. return false
  242. }
  243. return true
  244. },
  245. slots: {
  246. default: () => (
  247. <>
  248. {imageUrl2.value ? <img src={imageUrl2.value} class="avatar" /> : null}
  249. {!imageUrl2.value ? (
  250. <ElIcon class="avatar-uploader-icon" size="large" style="font-size: 50px">
  251. +
  252. </ElIcon>
  253. ) : null}
  254. </>
  255. ),
  256. tip: () => <div class="el-upload__tip">上传格式:png、jpg,大小:56x56px;</div>
  257. }
  258. }
  259. },
  260. {
  261. field: 'jsonValue',
  262. label: '材质内容',
  263. component: 'Input',
  264. colProps: {
  265. span: 24
  266. },
  267. componentProps: {
  268. type: 'textarea',
  269. rows: 4,
  270. placeholder: '请输入材质内容'
  271. },
  272. formItemProps: {
  273. rules: [required()]
  274. }
  275. }
  276. ])
  277. const schema2 = reactive<FormSchema[]>([
  278. {
  279. field: 'jsonPath',
  280. component: 'Upload',
  281. label: '材质内容',
  282. colProps: {
  283. span: 24
  284. },
  285. componentProps: {
  286. limit: 1,
  287. action: PATH_URL + '/resource/manage/addModelCompress',
  288. headers: headers,
  289. fileList: [],
  290. multiple: true,
  291. onPreview: (uploadFile) => {
  292. console.log(uploadFile)
  293. },
  294. onRemove: async (file) => {
  295. const formData = await getFormData()
  296. formData.jsonPath = ''
  297. formData.compressFileName = ''
  298. formData.uploadCompress = false
  299. },
  300. onSuccess: async (_response, uploadFile) => {
  301. console.log('kankan_response', uploadFile)
  302. const formData = await getFormData()
  303. formData.compressFilePath = _response.data
  304. },
  305. beforeRemove: (uploadFile) => {},
  306. onExceed: (files, uploadFiles) => {
  307. ElMessage.warning('只能上传一个资源,请移除后重新上传')
  308. },
  309. beforeUpload: (rawFile) => {
  310. if (rawFile.type !== 'application/x-zip-compressed' && rawFile.name.indexOf('.rar') == -1) {
  311. ElMessage.error('只能上传RAR、ZIP文件')
  312. return false
  313. }
  314. return true
  315. },
  316. slots: {
  317. default: () => <BaseButton type="primary">点击上传</BaseButton>,
  318. tip: () => <div class="el-upload__tip">文件类型:RAR\ZIP</div>
  319. }
  320. }
  321. }
  322. ])
  323. //编辑
  324. const edittab = async (data: TableSlotDefault) => {
  325. console.log('shanchu', data)
  326. isedit.value = '编辑'
  327. dialogVisible.value = true
  328. const formRef = await getElFormExpose()
  329. const formData = await getFormData()
  330. formData.compressFileName = data.row.compressFileName
  331. formData.jsonPath = data.row.jsonPath
  332. formData.TIETU = data.row.jsonValue.texture
  333. formData.materialName = data.row.materialName
  334. let a = JSON.parse(JSON.stringify(data.row.jsonValue))
  335. tietu.value = a.texture
  336. imageUrl2.value = PATH_URL + data.row.jsonValue.texture
  337. delete a.texture
  338. formData.jsonValue = JSON.stringify(a)
  339. formData.materialType = data.row.materialType
  340. formData.materialIcon = data.row.materialIcon.replace(PATH_URL, '')
  341. imageUrl.value = data.row.materialIcon
  342. formData.materialId = data.row.materialId
  343. schema[1].componentProps.fileList = [
  344. {
  345. name: data.row.compressFileName,
  346. url: data.row.jsonPath
  347. }
  348. ]
  349. // 如果材质类型是颜色,不显示贴图图标
  350. if (formData.materialType === 2) {
  351. schema.find((item) => item.field === 'TIETU').colProps.span = 0
  352. } else {
  353. schema.find((item) => item.field === 'TIETU').colProps.span = 24
  354. }
  355. }
  356. // 添加编辑模板管理
  357. const signIn = async () => {
  358. const formRef = await getElFormExpose()
  359. const formData = await getFormData()
  360. console.log('asdhajgsh', formData.jsonValue)
  361. if (!formData.TIETU && formData.materialType == 1) {
  362. ElMessage.warning('请上传贴图图标')
  363. return
  364. }
  365. try {
  366. formData.jsonValue = JSON.parse(formData.jsonValue)
  367. } catch (error) {
  368. ElMessage.error('材质内容格式错误')
  369. return
  370. }
  371. console.log('shdjasd1', formData.TIETU)
  372. if (formData.TIETU) {
  373. formData.jsonValue.texture = formData.TIETU
  374. } else {
  375. formData.jsonValue.texture = tietu.value
  376. }
  377. //如果是编辑去掉icon的拼接
  378. console.log('kakkkkak', formData)
  379. await formRef?.validate(async (isValid) => {
  380. if (isValid) {
  381. const res = await saveResource(formData)
  382. console.log('shdjasd22', res)
  383. if (res) {
  384. dialogVisible.value = false
  385. ElMessage.success('保存成功')
  386. refresh()
  387. } else {
  388. console.log('asdhjasd')
  389. delete formData.jsonValue.texture
  390. formData.jsonValue = JSON.stringify(formData.jsonValue)
  391. }
  392. }
  393. })
  394. }
  395. // 批量添加材质
  396. const signIn2 = async () => {
  397. const formRef = await getElFormExpose()
  398. const formData = await getFormData()
  399. //如果是编辑去掉icon的拼接
  400. console.log('kakkkkak', formData)
  401. await formRef?.validate(async (isValid) => {
  402. if (isValid) {
  403. const res = await batchsavecz(formData)
  404. if (res) {
  405. dialogVisible2.value = false
  406. refresh()
  407. }
  408. }
  409. })
  410. }
  411. //多选删除
  412. const getSelections = async () => {
  413. const elTableRef = await getElTableExpose()
  414. const selections = elTableRef?.getSelectionRows()
  415. let arr = {
  416. materialIds: []
  417. }
  418. if (selections) {
  419. arr.materialIds = selections.map((item) => {
  420. return item.materialId
  421. })
  422. }
  423. if (arr.materialIds.length !== 0) {
  424. ElMessageBox.confirm('确定删除所选数据?')
  425. .then(async () => {
  426. console.log('kankan', arr)
  427. const res = await deleteResource(arr)
  428. console.log('kkkkkkss', res)
  429. if (res.code == 200) {
  430. ElMessage.success('删除成功')
  431. }
  432. refresh()
  433. })
  434. .catch(() => {
  435. // catch error
  436. })
  437. } else {
  438. ElMessage.warning('请选择数据')
  439. }
  440. }
  441. const options = [
  442. {
  443. value: 1,
  444. label: '贴图'
  445. },
  446. {
  447. value: 2,
  448. label: '颜色'
  449. }
  450. ]
  451. //搜索
  452. const handersearch = function () {
  453. tableState.currentPage.value = 1
  454. refresh()
  455. }
  456. const tianjia = async () => {
  457. imageUrl.value = ''
  458. imageUrl2.value = ''
  459. isedit.value = '添加'
  460. schema[1].componentProps.fileList = []
  461. dialogVisible.value = true
  462. }
  463. </script>
  464. <template>
  465. <ContentWrap>
  466. <div style="margin-bottom: 10px">
  467. <span style="color: #606266"> 材质名称:</span>
  468. <el-input
  469. v-model="text"
  470. style="width: 200px; height: 43px; margin: 7px"
  471. placeholder="请输入材质名称"
  472. />
  473. <span style="color: #606266"> 材质状态:</span>
  474. <el-select
  475. v-model="materialType"
  476. clearable
  477. placeholder="全部"
  478. size="large"
  479. style="width: 240px"
  480. >
  481. <el-option
  482. v-for="item in options"
  483. :key="item.value"
  484. :label="item.label"
  485. :value="item.value"
  486. />
  487. </el-select>
  488. <ElButton
  489. style="margin-left: 20px"
  490. type="primary"
  491. size="large"
  492. @click="handersearch"
  493. :icon="Search"
  494. >搜索</ElButton
  495. >
  496. <ElButton type="success" size="large" @click="tianjia" :icon="Edit">添加</ElButton>
  497. <ElButton type="danger" size="large" @click="getSelections" :icon="Delete">删除</ElButton>
  498. </div>
  499. <Table
  500. v-model:pageSize="pageSize"
  501. v-model:currentPage="currentPage"
  502. :columns="columns"
  503. :image-preview="['icon']"
  504. :data="dataList"
  505. row-key="id"
  506. headerAlign="center"
  507. align="center"
  508. :loading="loading"
  509. sortable
  510. :pagination="{
  511. total: total
  512. }"
  513. @register="tableRegister"
  514. @refresh="refresh"
  515. />
  516. </ContentWrap>
  517. <Dialog v-model="dialogVisible" maxHeight="580px" width="35rem" :title="isedit">
  518. <Form :schema="schema" @register="formRegister" />
  519. <template #footer>
  520. <div style="width: 100%; display: flex; justify-content: center">
  521. <BaseButton
  522. style="font-size: 1rem; height: 2.2rem; margin: auto"
  523. type="primary"
  524. class="w-[15%]"
  525. @click="signIn"
  526. >
  527. 确定
  528. </BaseButton>
  529. </div>
  530. </template>
  531. </Dialog>
  532. <Dialog v-model="dialogVisible2" maxHeight="390px" width="35rem" :title="isedit">
  533. <Form :schema="schema2" @register="formRegister" />
  534. <template #footer>
  535. <div style="width: 100%; display: flex; justify-content: center">
  536. <BaseButton
  537. style="font-size: 1rem; height: 2.2rem; margin: auto"
  538. type="primary"
  539. class="w-[15%]"
  540. @click="signIn2"
  541. >
  542. 确定
  543. </BaseButton>
  544. </div>
  545. </template>
  546. </Dialog>
  547. </template>
  548. <style>
  549. .el-image__preview {
  550. width: 56px !important;
  551. height: 56px !important;
  552. }
  553. </style>
  554. <style lang="less">
  555. .el-upload {
  556. position: relative;
  557. overflow: hidden;
  558. cursor: pointer;
  559. border: 1px dashed var(--el-border-color);
  560. border-radius: 6px;
  561. transition: var(--el-transition-duration-fast);
  562. }
  563. .el-upload:hover {
  564. border-color: var(--el-color-primary);
  565. }
  566. .el-icon.avatar-uploader-icon {
  567. width: 120px;
  568. height: 120px;
  569. font-size: 28px;
  570. color: #8c939d;
  571. text-align: center;
  572. }
  573. .avatar {
  574. width: 120px;
  575. height: 120px;
  576. }
  577. </style>