From 0397897ca9b66a70f969d4b16aa24301bd3b8878 Mon Sep 17 00:00:00 2001 From: zq <136432190602163.com> Date: Tue, 22 Jul 2025 15:54:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=8F=90=E7=A4=BA=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E3=80=81=E5=A4=8D=E5=88=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/src/App.vue | 1470 +++++++++++++++++----------------- packages/GuipFormItem/index.js | 7 + packages/GuipFormItem/src/index.vue | 52 ++ packages/GuipMessage/GuipMessage.vue | 170 ++++ packages/GuipMessage/index.js | 94 +++ packages/assets/dropDown_expand.png | Bin 673 -> 297 bytes packages/assets/message_Success.png | Bin 0 -> 802 bytes packages/assets/message_Warning.png | Bin 0 -> 654 bytes packages/assets/message_error.png | Bin 0 -> 746 bytes packages/index.js | 41 +- packages/styles/component.scss | 85 +- packages/utils/clipboard.js | 77 ++ packages/utils/common.js | 32 + packages/utils/dirClipBoard.js | 19 + packages/utils/eventBus.js | 11 + packages/utils/headerIcon.js | 17 + packages/utils/request.js | 93 +++ 17 files changed, 1450 insertions(+), 718 deletions(-) create mode 100644 packages/GuipFormItem/index.js create mode 100644 packages/GuipFormItem/src/index.vue create mode 100644 packages/GuipMessage/GuipMessage.vue create mode 100644 packages/GuipMessage/index.js create mode 100644 packages/assets/message_Success.png create mode 100644 packages/assets/message_Warning.png create mode 100644 packages/assets/message_error.png create mode 100644 packages/utils/clipboard.js create mode 100644 packages/utils/common.js create mode 100644 packages/utils/dirClipBoard.js create mode 100644 packages/utils/eventBus.js create mode 100644 packages/utils/headerIcon.js create mode 100644 packages/utils/request.js diff --git a/examples/src/App.vue b/examples/src/App.vue index 375e998..6230560 100644 --- a/examples/src/App.vue +++ b/examples/src/App.vue @@ -105,6 +105,35 @@ + 提示框: + + 成功提示 + 失败提示 + 警告提示 + + + + + 复制功能 + + copy固定内容 + + 复制渝过田晴 + + + 点击复制: {{ content }} + + + 手动点击copy + + + + + + + + + 实时预览tab组件 @@ -153,7 +182,18 @@ - + + + + + 自定义表单展示形式: + + + + 跳转一下 自定义右侧 + + + @@ -307,660 +347,660 @@ @@ -999,117 +1039,119 @@ h2 { padding-bottom: 10px; border-bottom: 1px solid #f0f0f0; } + .elementWrap { - /* width: 100%; */ - padding: 30px 40px; - background: #fff; + /* width: 100%; */ + padding: 30px 40px; + background: #fff; - .ele-item { - display: flex; - align-items: center; - justify-content: flex-start; - margin: 20px 0 30px; + .ele-item { + display: flex; + align-items: center; + justify-content: flex-start; + margin: 20px 0 30px; - label { - font-size: 16px; - font-weight: bold; - width: 100px; - margin-right: 10px; - text-align: left; - } + label { + font-size: 16px; + font-weight: bold; + width: 100px; + margin-right: 10px; + text-align: left; } + } } // 组合框样式 start // input drop组合使用 .combo-formItem { - ::v-deep { - .form-item-bottom { - position: relative; - } - - .select-trigger { - background: #F6F7FA; - border-color: transparent; - } + ::v-deep { + .form-item-bottom { + position: relative; + } - .is-open .select-trigger { - border-color: #006AFF; - } + .select-trigger { + background: #F6F7FA; + border-color: transparent; + } - .el-input__inner { - border-radius: 2px 0 0 2px; - } + .is-open .select-trigger { + border-color: #006AFF; } - .self-drop-wrap { - position: absolute; - z-index: 1; - width: 100%; + .el-input__inner { + border-radius: 2px 0 0 2px; } + } - .appendDrop { - height: 38px; - align-items: center; - border-radius: 0 2px 2px 0; - border: 1px solid #DFE2E6; - border-left-color: transparent; - justify-content: center; - box-sizing: border-box; - padding: 0 30px 0 12px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; + .self-drop-wrap { + position: absolute; + z-index: 1; + width: 100%; + } - &:hover { - border: 1px solid #006AFF; - } + .appendDrop { + height: 38px; + align-items: center; + border-radius: 0 2px 2px 0; + border: 1px solid #DFE2E6; + border-left-color: transparent; + justify-content: center; + box-sizing: border-box; + padding: 0 30px 0 12px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + + &:hover { + border: 1px solid #006AFF; } + } } // 组合框样式 end .ScaleBox { - width: 1000px; - background-size: 100% 100%; - -ms-transition: 0.3s; - transition: 0.3s; - -ms-transform-origin: 0 0; - transform-origin: 0 0; - margin: 0 auto; + width: 1000px; + background-size: 100% 100%; + -ms-transition: 0.3s; + transition: 0.3s; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + margin: 0 auto; } .cardfooter { - width: 100%; - bottom: 20px; - right: 30px; - text-align: right; - justify-content: center; + width: 100%; + bottom: 20px; + right: 30px; + text-align: right; + justify-content: center; } .btn1 { - cursor: pointer; - font-weight: bold; - width: 114px; - height: 40px; - /* 自动布局 */ - display: flex; - align-items: center; - padding: 11px 12px; - box-sizing: border-box; - color: #FFFFFF; - border-radius: 4px; - transition: all .3s; - background: linear-gradient(290deg, #FF4143 4%, #FF768B 92%); + cursor: pointer; + font-weight: bold; + width: 114px; + height: 40px; + /* 自动布局 */ + display: flex; + align-items: center; + padding: 11px 12px; + box-sizing: border-box; + color: #FFFFFF; + border-radius: 4px; + transition: all .3s; + background: linear-gradient(290deg, #FF4143 4%, #FF768B 92%); - &:hover { - opacity: 0.7; - background: linear-gradient(290deg, #FF4143 4%, #FF768B 92%); - } + &:hover { + opacity: 0.7; + background: linear-gradient(290deg, #FF4143 4%, #FF768B 92%); + } } -.btns{ - display: flex; - justify-content: flex-end; - align-items: center; + +.btns { + display: flex; + justify-content: flex-end; + align-items: center; } \ No newline at end of file diff --git a/packages/GuipFormItem/index.js b/packages/GuipFormItem/index.js new file mode 100644 index 0000000..bfe6152 --- /dev/null +++ b/packages/GuipFormItem/index.js @@ -0,0 +1,7 @@ +import GuipFormItem from './src/index.vue' + +GuipFormItem.install = function(Vue) { + Vue.component(GuipFormItem.name || 'GuipFormItem', GuipFormItem) +} + +export default GuipFormItem \ No newline at end of file diff --git a/packages/GuipFormItem/src/index.vue b/packages/GuipFormItem/src/index.vue new file mode 100644 index 0000000..50146bc --- /dev/null +++ b/packages/GuipFormItem/src/index.vue @@ -0,0 +1,52 @@ + + + + {{ label }} + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/GuipMessage/GuipMessage.vue b/packages/GuipMessage/GuipMessage.vue new file mode 100644 index 0000000..256bead --- /dev/null +++ b/packages/GuipMessage/GuipMessage.vue @@ -0,0 +1,170 @@ + + + + + + {{ message }} + + + + + + + \ No newline at end of file diff --git a/packages/GuipMessage/index.js b/packages/GuipMessage/index.js new file mode 100644 index 0000000..094216d --- /dev/null +++ b/packages/GuipMessage/index.js @@ -0,0 +1,94 @@ +import Vue from 'vue' +import GuipMessage from './GuipMessage.vue' + +// 默认图标配置 +const defaultIcons = { + success: 'icon-success', // 替换为你的图标类名 + info: 'icon-info', + warning: 'icon-warning', + error: 'icon-error' +} + +// 默认图片配置 +const defaultImages = { + success: require('../assets/message_Success.png'), + info: require('../assets/message_Warning.png'), + warning: require('../assets/message_Warning.png'), + error: require('../assets/message_error.png') +} +const MessageConstructor = Vue.extend(GuipMessage) + +// let messageInstance = null +let messageQueue = [] + +function showMessage(options) { + if (typeof options === 'string') { + options = { + message: options + } + } + + // 合并默认配置 + const config = { + type: 'info', + duration: 3000, + position: 'top-center', + showImage: true, + ...options + } + + // 设置图标或图片 + if (config.showImage) { + config.imageUrl = options.imageUrl || defaultImages[config.type] + } else { + config.iconClass = options.iconClass || defaultIcons[config.type] + } + + // 创建实例 + const instance = new MessageConstructor({ + propsData: config + }) + + // 挂载到DOM + instance.$mount() + document.body.appendChild(instance.$el) + + // 添加到队列 + messageQueue.push(instance) + + // 返回关闭方法 + return { + close: () => instance.close() + } +} + +function install(Vue, options = {}) { + // 合并默认配置 + if (options.icons) { + Object.assign(defaultIcons, options.icons) + } + if (options.images) { + Object.assign(defaultImages, options.images) + } + + // 添加全局方法 + Vue.prototype.$Message = showMessage + Vue.prototype.$Message.closeAll = () => { + messageQueue.forEach(instance => instance.close()) + messageQueue = [] + } + + // 添加快捷方法 + const types = ['success', 'info', 'warning', 'error'] + types.forEach(type => { + Vue.prototype.$Message[type] = (message, options = {}) => { + return showMessage({ + message, + type, + ...options + }) + } + }) +} + +export default { install } \ No newline at end of file diff --git a/packages/assets/dropDown_expand.png b/packages/assets/dropDown_expand.png index ec5192d3876b4e6955030d733da61f7be7fb5c34..91553a3c36652e8a9c826b0b272663766b83b666 100644 GIT binary patch delta 282 zcmZ3;x{_&vL_G^L0|P^Zd(K-RB^}@s;tHe_G76H?N|I8Fl2VI-C^@+}8O%tqST6vS z<|qmB3uaL0Z@B+H;Jo+dgRMZZt)4E9As)xyPP7$ja^PtdpSdvY3iAoxE#BG31vPBj zY^|Q%*wB$96qm7L&du=DPv7^QZJRLlYr9qby=|Xef7dOjy1Mt3rpCjLwTawE1=~x7p`d+UdyBqTDUUbCw)DQFKdiufR;HbEezmHgbnA zYw=T`^dK-x*Q%STxm~omBOp@v-)rVJ^RRgF>s8&dbU^bL1W#x|x5~-EaPf)xpA> dHkD;Cgb4eEzft+I&>H9k22WQ%mvv4FO#tY$dGP=M delta 661 zcmV;G0&4xK0-*(v7=H)`00020X>r~F0004VQb$4nuFf3k00004b3#c}2nYxWd40byYBH3bc8TNM`LbaZlFjLjk_pg6{N!SWH24W48%8Z zTB>w(jC}+j0eWjUg(Wayf4quzrOfa@r7Tvf)#?QdFvb{TjDIo47-Nhv#@GiEP#;92 zEEKBu6-qs+o|?_BrmGg`)tK%4jSCQsvQQNAH-NA_^cX07zPb7F%g=P(N|NzV3;YDo zFAuGhERIZzAWQ>@wTSR?^8nD-0`oY{CvK%$@Hy9Wf07C2;k86Dz zr};(GN%|6}`F{npJ~e)*)RXCO&v>p_Uy4Ew@p>0*Xq_cr#)Co@$Nx(gqEQygLe90; zpNLads;6eA58jX9>khmflz6Y&)O4QaR{+55YPwRgI0}FzaY`r(xk!@nu-1$nN|NzV z6mkLL<^y24>miXlU|acaW#kD#aCUorKCv0gl{n2O@Obf?`+0vs(c_PO`?l9`noO|K}r{KbP+pB?H#bKjX1iB9mOhw6yI@l89Q=_CO=$p9Y-Irqc~Xr zz+I%;j(=?J2vS_c(P!)^&UV1Ie~F{-*ijlqkWx2}ZN!co+Q*<3n>YeM8?mE!T>!u; zYLr&~-F6m1ibWjX@DaOruGOBMaRj`@j^ZVPl$~+(7&}U&vdcTV#we#u#IaF~%7CF#Z62EqB|fW)3(900000NkvXXu0mjf1Kca^ diff --git a/packages/assets/message_Success.png b/packages/assets/message_Success.png new file mode 100644 index 0000000000000000000000000000000000000000..786586d874bb899dfc0a92bb39cb5c3c0dab8d55 GIT binary patch literal 802 zcmV+-1Ks?IP)Q(TKnB*PrOa&-39>)soRCbRYl# z01$LiPE!CtUyrZP-|sLWU~dq=fN=eaAS?g?0$WK$K~z}7t(e<(gCGz^6%is)L*gwq zwoU*4Ckw_XAoqCQ8tPum92gjq#G({rFh`hDgb>WYDTz@*AS1}a@LUFBNJR~*fIq7w zh+2eePt?VVnNb%H%*l!2%2OAo_Q7yvcB{OmvrMY^G^{mK#&tzPFkHmoRw#$k%OUeI z%;^-vp>&t00>^=n>RlekVI-N8#d0XEMNS&ek<%0%m=avX3KF%hrZUp8bxQC0@Be&HYtT3IP5Euxmj&h=^-Q@bCAiSJSN zvvD4p;oKKAZJbdzjyyqvVZYjcz==K~)ARW!{4E&vY_wlcJ?JTiU^i?5=@#~{9E4!l z&>A?}96gjU1jFvs2+|xNog9eEumuEdARfxLQw@gAg1Rjte9As{8^)DsH?2f+8^#6n zr}aa_8EhPWZfgtMeb|BiY#eMXwQZ+xMjK}?wT3I-RVGbV4n6a`nqjOF)?xo+=g`u6 zKyE9sYwVoLah)B#45QrqS>}>-e}TRo99%kY*zI5_t&-l?$kI|Jo7>d7IJi9e>XQ zC0ga5_YW^g&EyByNTrpG4lb8DK~1PAylY60YO{`O{Ellyk86%uo`QM+WO)WE0{Sgv zc|b@4TFE+bDD|2Y@_F65I5UNOo_(0g+KNIX;7tpdpT>wcWnrClk9DL7#JqF@8AOO} gXN+=~0qZN)Kl957Uiq5{WdHyG07*qoM6N<$f+3l9v;Y7A literal 0 HcmV?d00001 diff --git a/packages/assets/message_Warning.png b/packages/assets/message_Warning.png new file mode 100644 index 0000000000000000000000000000000000000000..0a4c25940280c43f26f23b4d1a3c2f70051defb3 GIT binary patch literal 654 zcmV;90&)F`P)P)t-s0002@ zfGqrkF8hKl`-3g}gDm=jE&GEl`hY6;fGGNcE&YQo|9~+2gDm-hEc${g`-3g}l1KjN z*Z=?j{@}{}(6Ima^8VPp{_o{>M0}?J000nlQchCvV$-PMKwmEF)G@s{r@jL-rA{cLx?hGKQn89kOW8)LaEAh4h9hb zbf${rj7qC#!cj(7E)rvF^r%*Rma~9_Ov6OABxXgm3``NkEXvamr{Q20W%N<8+}WKf zuZH!?l((*I3}%t_oK`Fcu@&*h<5O{lgZP!F(wqaq=h@}wI5X+U$?K}G^(!tW3dglXXL*&r2sK$xH`lxr?XC!w#53Cg8FAO$iB%79P~ z6#CEpJ4X=w8QCDQf)u+VVwX0R0Tpr&o7__yX!-h$bEmDUrB|a(y0snYJKD;HKS-A9 z^X=?WYWw`7`u$%r?m~zCu4fzRNSC@{949i@#&KG|?y;QOgCe~R5`;_BR!4*1BInHy z;|3c27KdT7IS=|6CB4B78))JLwhlEuQXtvpYasQeshh@e@E+Qaaa3yXlN&|lhT}O; zQDYkOX3ZkVK4l>Oi%wzPX9|y|4dN-O;7)( zr~lpF|Mc|#($oKAW&g*>|LE!eo1Fi=z5oCJ|88*1knr~a000qmQchCD7Cg}>22`;zjJV$wqghZRb-Mu;iTbIc}J;C$^eg#tK^My_)*WjJ;iYolm|Uf4=DJZEd{W_2cRJSkVss z7%M%x#!*k!A2Lde;H*hA$4i=B!sqE5`RB&5`EJ&vCC6Ox2yQ{1oZa+_Hu*_ z+Z=n%aY!Li92;%&D)W&@4m32#L!vo$y9F-SH7UTc`3Hz4g*X7^Kr)sSCW&&vZsIv1 zk|?(zi*1o&n|8O&i8)5vatE6)+E?U&L%RE7?JfDz5C8pCt6}rS6OaYzfk*WI3-as> z?1zM}{{vOdre4`>zWfD2iY_8#PgmH_hrZ*o=Bh7e&&RJavQKJ3Xot#`epU6AOU?KF z!>rS?(2i~#u~w~Q_T(CulhlMRB~e3Ks?93b_?2r#%QeR~PDxFP2s{II3H_D`JRnpF zt>jQ`=oICYh { if (!component.name) { throw new Error(`Component name is required: ${component}`) @@ -45,6 +78,7 @@ const install = function (Vue) { Vue.component(component.name, component) }) } +console.log(install,'install---'); export default { install, @@ -62,5 +96,6 @@ export default { GuipTable, GuipTooltip, GuipSwitch, - GuipDialog + GuipDialog, + GuipFormItem } \ No newline at end of file diff --git a/packages/styles/component.scss b/packages/styles/component.scss index 166c407..e878264 100644 --- a/packages/styles/component.scss +++ b/packages/styles/component.scss @@ -215,6 +215,7 @@ } } + .guip-svg-icon-wrapper .svg-icon ::v-deep path { fill: currentColor; } @@ -296,4 +297,86 @@ font-size: 12px; margin-left: 10px; } -} \ No newline at end of file +} + +// 自定义下拉选择框组件 start +.guip-custom-select { + height: 38px; + position: relative; + font-family: Arial, sans-serif; + + .select-trigger { + border-radius: 2px; + opacity: 1; + background: #FFFFFF; + border: 1px solid #DFE2E6; + width: 100%; + height: 40px; + box-sizing: border-box; + padding: 10px 12px; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; + } + + .is-open .select-trigger { + border: 1px solid #006AFF; + transition: all .5s; + outline: 3px solid #D8E9FA; + } + + .select-trigger:hover { + border-color: #006AFF; + transition: all .5s; + } + + .arrow-icon { + width: 12px; + } + + .select-dropdown { + position: absolute; + top: 100%; + right: 0; + width: 100%; + border: 1px solid #ccc; + box-sizing: border-box; + border-radius: 4px; + background-color: #fff; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + z-index: 1000; + margin-top: 4px; + max-height: 384px; + overflow-y: auto; + padding: 0 12px 12px 12px; + } + + .dropdown-item { + padding: 12px 10px; + cursor: pointer; + } + + .dropdown-item:hover { + background: #F6F7FA; + } + + .dropdown-item.is-selected { + background-color: #F6F7FA; + color: #006AFF; + } + + /* 展开收起动画 */ + .slide-fade-enter-active, + .slide-fade-leave-active { + transition: all 0.3s ease; + } + + .slide-fade-enter-from, + .slide-fade-leave-to { + opacity: 0; + transform: translateY(-10px); + } +} + +// 自定义下拉选择框组件 end \ No newline at end of file diff --git a/packages/utils/clipboard.js b/packages/utils/clipboard.js new file mode 100644 index 0000000..4c81896 --- /dev/null +++ b/packages/utils/clipboard.js @@ -0,0 +1,77 @@ +/** + * 复制文本到剪贴板 + * @param {string} text 要复制的文本 + * @param {Object} options 配置选项 + * @param {string} options.successMsg 成功提示信息 + * @param {string} options.errorMsg 失败提示信息 + * @param {Vue} options.vm Vue实例(用于调用$Message) + * @returns {Promise} 是否复制成功 + */ +export function copyToClipboard(text, options = {}) { + const { + successMsg = '复制成功', + errorMsg = '复制失败,请手动复制', + vm = null + } = options; + + return new Promise((resolve) => { + // 创建textarea元素 + const textarea = document.createElement('textarea'); + textarea.value = text; + textarea.style.position = 'fixed'; // 防止页面滚动 + document.body.appendChild(textarea); + textarea.select(); + + try { + // 执行复制命令 + const successful = document.execCommand('copy'); + console.log(vm,'vm.$Message---'); + if (successful) { + if (vm && vm.$Message) { + vm.$Message.success(successMsg); + } else { + console.log(successMsg); + } + resolve(true); + } else { + throw new Error('Copy command was unsuccessful'); + } + } catch (err) { + console.error('复制失败11:', err); + if (vm && vm.$Message) { + vm.$Message.error(errorMsg); + } else { + console.error(errorMsg); + } + resolve(false); + } finally { + document.body.removeChild(textarea); + } + }); +} + +/** + * @param {string} text 要复制的文本 + * @param {Object} options 配置选项 + * @returns {Promise} 是否复制成功 + */ +export async function modernCopyToClipboard(text, options = {}) { + const { + successMsg = '复制成功', + errorMsg = '复制失败,请手动复制', + vm = null + } = options; + if (navigator.clipboard && window.isSecureContext) { + // 注意:localhost 可能会无效 或者 提示复制失败,但是其实已经复制到粘贴板 + await navigator.clipboard.writeText(text); + if (vm && vm.$Message) { + vm.$Message.success(successMsg); + } else { + console.log(errorMsg); + } + } else { + return copyToClipboard(text, options); + } +} + +export default modernCopyToClipboard; \ No newline at end of file diff --git a/packages/utils/common.js b/packages/utils/common.js new file mode 100644 index 0000000..f2af514 --- /dev/null +++ b/packages/utils/common.js @@ -0,0 +1,32 @@ +// 设置页面元素对应高亮 +export function setHighActive(dom) { + const ele = document.getElementById(dom) + ele.classList.add('ceshi') + ele.scrollIntoView({behavior:'smooth',block:'start'}) + setTimeout(()=>{ + ele.classList.remove('ceshi') + },1000) +} + +export function getServicePriceDesc(price, price_unit, unit_num) { + let unit = 0; + let unit_str = ""; + + if (unit_num == 1) return price + price_unit +'/篇'; + + if (unit_num/10000 < 10) { + unit = Math.ceil(unit_num/10000); + unit_str = unit == 1 ? '万' : unit+'万'; + } + if (unit_num/1000 < 10) { + unit = Math.ceil(unit_num/1000); + unit_str = unit == 1 ? '千' : unit+'千'; + } + if (unit_num/100 < 10) { + unit = Math.ceil(unit_num/100); + unit_str = unit == 1 ? '百' : unit+'百'; + } + + return price + price_unit + "/" +unit_str + "字符"; +} + diff --git a/packages/utils/dirClipBoard.js b/packages/utils/dirClipBoard.js new file mode 100644 index 0000000..73ddd76 --- /dev/null +++ b/packages/utils/dirClipBoard.js @@ -0,0 +1,19 @@ +import modernCopyToClipboard from './clipboard'; + +export default { + install(Vue) { + Vue.directive('clipboard', { + bind(el, binding) { + el.style.cursor = 'pointer'; + el.addEventListener('click', async () => { + const text = binding.value || el.innerText; + const options = { + vm: binding.instance, + ...(binding.arg || {}) + }; + await modernCopyToClipboard(text, options); + }); + } + }); + } +}; \ No newline at end of file diff --git a/packages/utils/eventBus.js b/packages/utils/eventBus.js new file mode 100644 index 0000000..2919ea8 --- /dev/null +++ b/packages/utils/eventBus.js @@ -0,0 +1,11 @@ +import Vue from 'vue' +// 创建全局事件总线 +const EventBus = new Vue() + +// 封装常用方法 +export const $on = EventBus.$on.bind(EventBus) +export const $once = EventBus.$once.bind(EventBus) +export const $off = EventBus.$off.bind(EventBus) +export const $emit = EventBus.$emit.bind(EventBus) + +export default EventBus \ No newline at end of file diff --git a/packages/utils/headerIcon.js b/packages/utils/headerIcon.js new file mode 100644 index 0000000..b1fe542 --- /dev/null +++ b/packages/utils/headerIcon.js @@ -0,0 +1,17 @@ +export default { + methods: { + renderHeaderWithIcon(h, { column }, iconPath) { + return h('div', [ + column.label, + h('img', { + attrs: { src: iconPath }, + style: { + width: '10px', + height: '10px', + marginLeft: '3px', + } + }) + ]) + } + } + } \ No newline at end of file diff --git a/packages/utils/request.js b/packages/utils/request.js new file mode 100644 index 0000000..28c3458 --- /dev/null +++ b/packages/utils/request.js @@ -0,0 +1,93 @@ +// src/utils/request.js +import axios from "axios"; + +// 创建 axios 实例 +const service = axios.create({ + baseURL: process.env.VUE_APP_BASE_API, // 从环境变量中读取 API 基础地址 + timeout: 60000, // 请求超时时间 + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, +}); + +// 请求拦截器 +service.interceptors.request.use( + (config) => { + // 在发送请求之前做一些处理,例如添加 token + const token = localStorage.getItem("token"); + if (token) { + config.headers["Auth"] = `${token}`; + } + return config; + }, + (error) => { + // 对请求错误做些什么 + return Promise.reject(error); + } +); + +// 响应拦截器 +service.interceptors.response.use( + (response) => { + // 对响应数据做一些处理 + const res = response.data; + if (!res.status) { + // 如果返回的 status 不是 true,则视为错误 + // return Promise.reject(new Error(res.info || "请求失败")); + } + return res; + }, + (error) => { + // 对响应错误做些什么 + if (error.response) { + switch (error.response.status) { + case 401: + // 未授权,跳转到登录页 + window.location.href = "/login"; + break; + case 404: + // 资源未找到 + console.error("资源未找到"); + break; + case 500: + // 服务器错误 + console.error("服务器错误"); + break; + default: + console.error("请求失败", error.message); + } + } + return Promise.reject(error); + } +); + +/** + * 封装请求方法 + * @param {string} method 请求方法 (GET, POST, PUT, DELETE 等) + * @param {string} url 请求地址 + * @param {object} data 请求参数 + * @param {object} config 其他 axios 配置 + * @returns {Promise} 返回请求结果 + */ +const request = (method, url, data = {}, config = {}) => { + const lowerCaseMethod = method.toLowerCase(); + if (lowerCaseMethod === "get") { + // GET 请求将参数拼接到 URL 上 + return service({ + method: "get", + url, + params: data, + ...config, + }); + } else { + // 其他请求(POST, PUT, DELETE 等)将参数放在请求体中 + return service({ + method: lowerCaseMethod, + url, + data, + ...config, + }); + } +}; + +export default request; \ No newline at end of file