From 553ce1daabe93466b178a9188cfd4883eef4c9da Mon Sep 17 00:00:00 2001 From: BianLzhaoMin <11485688+bianliangzhaomin123@user.noreply.gitee.com> Date: Fri, 12 Sep 2025 16:44:10 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 1 + .env.production | 3 +- package.json | 1 + src/api/dataManage/pro-materials.js | 5 +- .../images/publicService/arrow-left.png | Bin 0 -> 1108 bytes .../images/publicService/arrow-right.png | Bin 0 -> 1096 bytes src/assets/images/publicService/go-back.png | Bin 0 -> 429 bytes src/components/ImagePreview/index.vue | 9 +- src/layout/components/Navbar.vue | 352 ++++++----- src/router/index.js | 60 +- src/utils/aes.js | 63 ++ src/utils/base64Utils.js | 56 ++ src/utils/request.js | 5 +- src/utils/request_formdata.js | 5 +- .../components/addAndEditForm.vue | 57 +- src/views/dataManage/pro-materials/index.vue | 13 +- src/views/login.vue | 9 +- src/views/publicService/index.vue | 12 +- .../components/card-container.vue | 444 ++++++++++++-- .../components/case-container.vue | 255 +++++++- .../publicService/productCenter/index.vue | 471 +++++--------- .../publicService/productCenter/index_old.vue | 465 ++++++++++++++ .../productCenter/product-case-list.vue | 212 +++++++ .../productCenter/product-detail.vue | 580 ++++++++---------- 24 files changed, 2106 insertions(+), 972 deletions(-) create mode 100644 src/assets/images/publicService/arrow-left.png create mode 100644 src/assets/images/publicService/arrow-right.png create mode 100644 src/assets/images/publicService/go-back.png create mode 100644 src/utils/aes.js create mode 100644 src/utils/base64Utils.js create mode 100644 src/views/publicService/productCenter/index_old.vue create mode 100644 src/views/publicService/productCenter/product-case-list.vue diff --git a/.env.development b/.env.development index 55b869e..1fa02b0 100644 --- a/.env.development +++ b/.env.development @@ -3,6 +3,7 @@ VUE_APP_TITLE = 公共服务平台 # 开发环境配置 ENV = 'development' +VUE_APP_ENV = 'development' # 公共服务平台/开发环境 VUE_APP_BASE_API = '/dev-api' diff --git a/.env.production b/.env.production index 7eac2ad..4887fab 100644 --- a/.env.production +++ b/.env.production @@ -3,6 +3,7 @@ VUE_APP_TITLE = 公共服务平台 # 生产环境配置 ENV = 'production' +VUE_APP_ENV = 'production' # 公共服务平台/生产环境 -VUE_APP_BASE_API = '/prod-api' +VUE_APP_BASE_API = '/bnscloud' diff --git a/package.json b/package.json index 95e7d54..b7d2292 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "axios": "0.28.1", "clipboard": "2.0.8", "core-js": "3.37.1", + "crypto-js": "^4.2.0", "echarts": "5.4.0", "element-ui": "2.15.14", "file-saver": "2.0.5", diff --git a/src/api/dataManage/pro-materials.js b/src/api/dataManage/pro-materials.js index d3836ef..7f0c271 100644 --- a/src/api/dataManage/pro-materials.js +++ b/src/api/dataManage/pro-materials.js @@ -46,9 +46,10 @@ export function getProductCenterDetailAPI(id) { } // 获取产品列表 -export function getProductListAPI() { +export function getProductListAPI(data) { return request({ - url: '/select/selectProduct', + url: `/select/selectProduct`, method: 'POST', + data, }) } diff --git a/src/assets/images/publicService/arrow-left.png b/src/assets/images/publicService/arrow-left.png new file mode 100644 index 0000000000000000000000000000000000000000..e5e3e1a26773a5eb07bc8442cdb3c2dc59144de3 GIT binary patch literal 1108 zcmV-a1grarP)zfK-*K-V*K|AEnU3eT=Y5~^eEfLd=RF^a(E0QG{bt}g zUSy7a` z(BBc`02+Z5%)^S7kUx|+64k=~1$YdU0ea;$0<6HO$K$Dj-cz)Mb~u7a3h)TVmw*L` zRSFXm6Yb0i?7CVZ2_YZ{)rWyLz-VDkZX;{_ms?9n?V**Gm80+?nP|2Lp%DptZ#YnE zM}U@)n3Pe!j%sV*;(n?&)aFTMO_NFp%a)RmkZ^~Vg8*yy_xC5UHVK(BGBPev$M0p zX0r*m+pQ;;rJOmQ}GCx1hw^j8OR@Bwi_2aaC+rAwA zh@_gDnnZ4HZp2AYd$O~$^ECt16>>NnUboxbMZ-a0YHF&hx3_nVwN*kG`1AAg-!3mN z^9vKx9TL|Gw)ROuLBV@jgoL&}p<7y7ZsBuxOkRw)Mk70$o11TI>i9{BbCU883=FLG z_4T!2PouhfGf|{q4Xf39g*5{)CbDE9Igg9zgCf*1(SZKzM*VXtS$?q=AGae0IBiEiEnWrpx7O z#9n`uPSI*Sr>5~#XiiN{?O<-?k+q~&7ll0}4b-Yp>s(S&@}auA`aEvySJ&6qKjE4# zLCj|y>yF~$;MMXu=@U2zT-Q9hX_be>^EA+xR zn)5fa5_o<13!4jD{hU7ZMa%_@#bTS7nDD?y){z9Li7op-00030|1BpwG5`Po21!Ig aR09C_Eg6;{Di5jv0000SoDKc zSY8DwOPS6Ku!>e$v`Vk89RiMm6i1nPO3+aP5}^=c|0Da zx3^cBot=#;K8he)eSQ5^#BI$`LPA0tI#C-oqvG@Vl%b&^(?nsGu0w!DotvA>vsf&r z(23g8)6lCQ?I$}UaNQzmape2{bp6@Ur1V%dBMJ+5W7%7uVK}HfI=J1w)H^zuD;RY#a zG2EaYKW~z}1yD?RdAX9AnW-mT#{N=Kz$1G`+wEekR;!^>cn_OX@nD-YlpRPiOAO0l znI~1eBstkJ0yD*se`#syqv~?G-ms$=W{V;J`1rU(#Rl|X*+%Jz7Ch404QzDJX!)RF zq^zuLhNnzfTwHvl9o+4Dd3jkp?eSw2GsKW@etw>BtKt<_sjaQ;$7%b*ATx7f(8#>U1w8Xi9du}@L{fq{Xwo}Qj2tm&Tb-Ygmk z2Mh>jV57eg+U!WB;#16p$_!R}B ze%961RpHLrCmbezai600MQ}(l+Ui1(bWo6l&*5;arKF_Xa=YCPSnIDc$Y_h_)HI$7 zjmgQ$ZLEztl1sK?Qn-htgRO9CgNuucKU7s!oyTqc+WPwXCyePbnOD92{ILEG&GMn3!1I+1YuL_bg2PE9`}FY|h`TO5pY3FMMt+ z^>fBB7C9GeHe27s#KZ<-B##upmI(U)0RRC1|LQcFN&o-=21!IgR09A;Pal@2?Vg!BC5|T$d1~fPKnbScw#QV?p&gU zeJp7Pc4pg>{zy0qEHswkuo6C)1q*2u%u}U~%y9%K3Us(llL0nQz@;jW@vaqj4}l+8 zQRA=#Rr+5PxT#&yi)Qf7hiJlA
@@ -33,6 +32,10 @@ export default { type: [Number, String], default: '', }, + borderRadius: { + type: [Number, String], + default: 0, + }, }, computed: { realSrc() { @@ -81,7 +84,7 @@ export default { diff --git a/src/router/index.js b/src/router/index.js index 9d30aab..e66d45d 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -109,6 +109,15 @@ export const constantRoutes = [ ), name: 'ProductDetail', }, + // 产品中心 ---- 查看案例页面 + { + path: 'productCenter/caseList', + component: () => + import( + '@/views/publicService/productCenter/product-case-list.vue' + ), + name: 'ProductCaseList', + }, // 公共组件 { path: 'commonCom', @@ -147,56 +156,6 @@ export const constantRoutes = [ }, ], }, - - // 在路由配置中导航条的路由 - // { - // path: '/', - // component: Layout, // 布局组件,包含左侧菜单和顶部导航 - // hidden: true, // 隐藏左侧菜单项 - // children: [ - // { - // path: '/productCenter/index', - // component: () => import('@/views/psp/productCenter/index.vue'), - // }, - // { - // path: '/common/index', - // component: () => import('@/views/psp/common/index.vue'), - // }, - // // ... 其他子路由 - // ], - // }, - - // 在路由配置中添加产品详情页面路由 - // { - // path: '/psp/productCenter', - // component: Layout, - // redirect: '/psp/productCenter/index', - // name: 'ProductCenter', - // meta: { title: '产品中心', icon: 'product' }, - // hidden: true, // 隐藏左侧菜单项 - // children: [ - // { - // path: 'detail/:id(\\d+)', - // name: 'ProductDetail', - // component: () => - // import('@/views/psp/productCenter/product-detail'), - // meta: { - // title: '产品详情', - // activeMenu: '/psp/productCenter/index', - // }, - // }, - // { - // path: 'case/:id(\\d+)', - // name: 'ProductCase', - // component: () => - // import('@/views/psp/productCenter/product-case'), - // meta: { - // title: '产品案例', - // activeMenu: '/psp/productCenter/index', - // }, - // }, - // ], - // }, ] // 动态路由,基于用户权限动态去加载 @@ -289,4 +248,5 @@ export default new Router({ mode: 'history', // 去掉url中的# scrollBehavior: () => ({ y: 0 }), routes: constantRoutes, + base: process.env.VUE_APP_ENV === 'production' ? '/pubSerPlatform' : '', }) diff --git a/src/utils/aes.js b/src/utils/aes.js new file mode 100644 index 0000000..cc8912c --- /dev/null +++ b/src/utils/aes.js @@ -0,0 +1,63 @@ +import * as CryptoJS from 'crypto-js' +const cbc_key = CryptoJS.enc.Utf8.parse('zhgd@bonus@zhgd@bonus@1234567890') +const cbc_iv = CryptoJS.enc.Utf8.parse('1234567812345678') +/** + * 加解密开关 + * 默认参数需要加密 + * @type {boolean} + */ +const jia_mi = false +/** + * 默认后台会自动加密 + * @type {boolean} + */ +const jie_mi = false +/** + * 加密 + * @param word + * @returns {string} + */ +export const encryptCBC = function (word) { + if (!jia_mi) { + return word + } + const srcs = CryptoJS.enc.Utf8.parse(word) + const encrypted = CryptoJS.AES.encrypt(srcs, cbc_key, { + iv: cbc_iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7, + }) + return encrypted.toString() +} + +/** + * 解密 + * @param word + * @returns {*} + */ +export const decryptCBC = function (word) { + if (!jie_mi) { + return word + } + const encrypted = CryptoJS.AES.decrypt(word, cbc_key, { + iv: cbc_iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7, + }) + return encrypted.toString(CryptoJS.enc.Utf8) +} + +/** + * 文件预览专用 + * @param word + * @returns {string} + */ +export const encryptCBCTime = function (word) { + const srcs = CryptoJS.enc.Utf8.parse(word) + const encrypted = CryptoJS.AES.encrypt(srcs, cbc_key, { + iv: cbc_iv, + mode: CryptoJS.mode.CBC, + padding: CryptoJS.pad.Pkcs7, + }) + return encrypted.toString() +} diff --git a/src/utils/base64Utils.js b/src/utils/base64Utils.js new file mode 100644 index 0000000..89fb80e --- /dev/null +++ b/src/utils/base64Utils.js @@ -0,0 +1,56 @@ +// base64Utils.js +let _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +const useBase64 = { + encode64:(e) => { + let t = ""; + let f = 0; + e = useBase64.encodeUTF8(e); + while (f < e.length) { + const n = e.charCodeAt(f++); + const r = e.charCodeAt(f++); + const i = e.charCodeAt(f++); + let s = n >> 2; + let o = (n & 3) << 4 | r >> 4; + let u = (r & 15) << 2 | i >> 6; + let a = i & 63; + if (isNaN(r)) { + u = a = 64; + } else if (isNaN(i)) { + a = 64; + } + t += _keyStr[s] + _keyStr[o] + _keyStr[u] + _keyStr[a]; + } + return t; + }, + decode64: (e) => { + let t = ""; + let f = 0; + e = e.replace(/[^A-Za-z0-9+/=]/g, ""); + while (f < e.length) { + const s = _keyStr.indexOf(e.charAt(f++)); + const o = _keyStr.indexOf(e.charAt(f++)); + const u = _keyStr.indexOf(e.charAt(f++)); + const a = _keyStr.indexOf(e.charAt(f++)); + let n = s << 2 | o >> 4; + let r = (o & 15) << 4 | u >> 2; + let i = (u & 3) << 6 | a; + t += String.fromCharCode(n); + if (u !== 64) { + t += String.fromCharCode(r); + } + if (a !== 64) { + t += String.fromCharCode(i); + } + } + return useBase64.decodeUTF8(t); + }, + + encodeUTF8: (input) => { + return unescape(encodeURIComponent(input)); + }, + + decodeUTF8: (input) => { + return decodeURIComponent(escape(input)); + }, +} +export default useBase64; diff --git a/src/utils/request.js b/src/utils/request.js index aea8700..8a8de19 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -121,7 +121,10 @@ service.interceptors.response.use( .then(() => { isRelogin.show = false store.dispatch('LogOut').then(() => { - location.href = '/index' + location.href = + process.env.VUE_APP_ENV === 'production' + ? '/pubSerPlatform/index' + : '/index' }) }) .catch(() => { diff --git a/src/utils/request_formdata.js b/src/utils/request_formdata.js index f17b0c0..333cd87 100644 --- a/src/utils/request_formdata.js +++ b/src/utils/request_formdata.js @@ -130,7 +130,10 @@ service.interceptors.response.use( .then(() => { isRelogin.show = false store.dispatch('LogOut').then(() => { - location.href = '/index' + location.href = + process.env.VUE_APP_ENV === 'production' + ? '/pubSerPlatform/index' + : '/index' }) }) .catch(() => { diff --git a/src/views/dataManage/pro-materials/components/addAndEditForm.vue b/src/views/dataManage/pro-materials/components/addAndEditForm.vue index a21990a..61cd42d 100644 --- a/src/views/dataManage/pro-materials/components/addAndEditForm.vue +++ b/src/views/dataManage/pro-materials/components/addAndEditForm.vue @@ -203,7 +203,7 @@ export default { }, created() { - this.getProductList() + // this.getProductList() }, methods: { @@ -249,14 +249,14 @@ export default { file.forEach((item) => { if (!item.id) { formData.append('files', item.raw) - fileMsg.push({ type: 1 }) + fileMsg.push({ type: 2 }) } }) cover.forEach((item) => { if (!item.id) { formData.append('files', item.raw) - fileMsg.push({ type: 2 }) + fileMsg.push({ type: 1 }) } }) @@ -267,7 +267,10 @@ export default { } } - formData.append('fileMsg', JSON.stringify(fileMsg)) + if (fileMsg.length > 0) { + formData.append('fileMsg', JSON.stringify(fileMsg)) + } + formData.append('params', JSON.stringify(params)) const API = @@ -275,14 +278,24 @@ export default { ? editProductCenterAPI : addProMaterialsAPI - const res = await API(formData) - console.log(res, 'res') + const loading = this.$loading({ + lock: true, + text: '文件正在上传中,请稍后...', + spinner: 'el-icon-loading', + background: 'rgba(0, 0, 0, 0.7)', + }) - if (res.code === 200) { - this.$modal.msgSuccess( - this.formType === 2 ? '编辑成功' : '新增成功', - ) - this.$emit('closeDialog', true) + try { + const res = await API(formData) + loading.close() + if (res.code === 200) { + this.$modal.msgSuccess( + this.formType === 2 ? '编辑成功' : '新增成功', + ) + this.$emit('closeDialog', true) + } + } catch (error) { + loading.close() } } catch (error) { // 校验失败,提示用户 @@ -295,11 +308,13 @@ export default { this.addAndEditForm.typeName = this.dict.type.tb_product_type.find( (item) => item.value === value, ).label + + this.getProductList(value) }, // 获取归属产品下拉选 - async getProductList() { - const res = await getProductListAPI() + async getProductList(typeId) { + const res = await getProductListAPI({ typeId }) this.productList = res.data }, @@ -342,20 +357,22 @@ export default { description, productName, file: files - .filter((e) => e.typeId === 1) - .map((item) => ({ - id: item.id, - url: item.filePath, - name: item.originalName, - })), - cover: files .filter((e) => e.typeId === 2) .map((item) => ({ id: item.id, url: item.filePath, name: item.originalName, })), + cover: files + .filter((e) => e.typeId === 1) + .map((item) => ({ + id: item.id, + url: item.filePath, + name: item.originalName, + })), } + + this.getProductList(typeId) // this.addAndEditForm.productId.forEach((item) => { // this.addAndEditForm.productName += // this.productList.find((j) => item == j.id).name + ',' diff --git a/src/views/dataManage/pro-materials/index.vue b/src/views/dataManage/pro-materials/index.vue index 32e6c1d..43c1c39 100644 --- a/src/views/dataManage/pro-materials/index.vue +++ b/src/views/dataManage/pro-materials/index.vue @@ -102,7 +102,14 @@ v-for="column in columns" > @@ -34,22 +74,115 @@ export default { cardList: { type: Array, - default: [], + default: () => [], + }, + + productId: { + type: [String, Number], + default: '', }, }, data() { return { - itemWidth: 100, + currentIndex: 0, // 当前显示的索引,从1开始(因为我们在开头添加了最后一个元素的副本) + transitionDuration: '0.5s', // 过渡动画时长 + timer: null, // 自动轮播计时器 + interval: 10000, // 轮播间隔时间(ms) } }, + computed: { + // 扩展列表:在开头添加最后一个元素的副本,在末尾添加第一个元素的副本,实现无缝滚动 + extendedCardList() { + if (this.cardList.length <= 1) return this.cardList + return [ + this.cardList[this.cardList.length - 1], // 最后一个元素的副本放在开头 + ...this.cardList, // 原始列表 + this.cardList[0], // 第一个元素的副本放在末尾 + ] + }, + }, mounted() { - this.getItemWidth() + // 启动自动轮播 + this.startAutoPlay() + + // 监听鼠标进入/离开,暂停/恢复自动轮播 + const container = this.$el.querySelector('.carousel-wrapper') + container.addEventListener('mouseenter', this.stopAutoPlay) + container.addEventListener('mouseleave', this.startAutoPlay) + }, + beforeDestroy() { + // 清理计时器 + this.stopAutoPlay() + + // 移除事件监听 + const container = this.$el.querySelector('.carousel-wrapper') + if (container) { + container.removeEventListener('mouseenter', this.stopAutoPlay) + container.removeEventListener('mouseleave', this.startAutoPlay) + } }, methods: { - // 动态获取 itemWidth - getItemWidth() { - this.itemWidth = this.$refs.cardItemImage[0].clientWidth + // 开始自动轮播 + startAutoPlay() { + this.stopAutoPlay() // 先清除已有计时器 + this.timer = setInterval(() => { + this.nextSlide() // 自动轮播方向:从左到右 + }, this.interval) + }, + + // 停止自动轮播 + stopAutoPlay() { + if (this.timer) { + clearInterval(this.timer) + this.timer = null + } + }, + + // 下一张(向右切换)- 从左到右显示 + nextSlide() { + // 当到达最后一个真实元素时,切换到复制的第一个元素 + if (this.currentIndex === this.cardList.length) { + this.transitionDuration = '0.5s' + this.currentIndex++ + + // 动画完成后,瞬间切换到真实的第一个元素 + setTimeout(() => { + this.transitionDuration = '0s' + this.currentIndex = 1 + }, 500) + } else { + this.transitionDuration = '0.5s' + this.currentIndex++ + } + }, + + // 上一张(向左切换)- 从右到左显示 + prevSlide() { + // 当在第一个真实元素时,先切换到复制的最后一个元素 + if (this.currentIndex === 1) { + this.transitionDuration = '0.5s' + this.currentIndex-- + + // 动画完成后,瞬间切换到真实的最后一个元素 + setTimeout(() => { + this.transitionDuration = '0s' + this.currentIndex = this.cardList.length + }, 500) + } else { + this.transitionDuration = '0.5s' + this.currentIndex-- + } + }, + + // 查看更多 + onHandleViewMore() { + this.$router.push({ + name: 'ProductCaseList', + query: { + id: this.productId, + }, + }) }, }, } @@ -58,7 +191,7 @@ export default { diff --git a/src/views/publicService/productCenter/index.vue b/src/views/publicService/productCenter/index.vue index 3180a04..5b0afdd 100644 --- a/src/views/publicService/productCenter/index.vue +++ b/src/views/publicService/productCenter/index.vue @@ -1,54 +1,49 @@