17 changed files with 1450 additions and 718 deletions
File diff suppressed because it is too large
@ -0,0 +1,7 @@ |
|||||
|
import GuipFormItem from './src/index.vue' |
||||
|
|
||||
|
GuipFormItem.install = function(Vue) { |
||||
|
Vue.component(GuipFormItem.name || 'GuipFormItem', GuipFormItem) |
||||
|
} |
||||
|
|
||||
|
export default GuipFormItem |
||||
@ -0,0 +1,52 @@ |
|||||
|
<template> |
||||
|
<div |
||||
|
:class="[{'column':column},{'error':hasError},{'w510':addClass=='w510'},{'w388':addClass=='w388'},'form-item1']"> |
||||
|
<div class="form-item-top"> |
||||
|
<label v-if="label" for="">{{ label }} |
||||
|
<img src="../../assets/require.svg" v-if="required" alt=""> |
||||
|
</label> |
||||
|
<template > |
||||
|
<slot name="formLeft"></slot> |
||||
|
</template> |
||||
|
<template > |
||||
|
<slot name="formRight"></slot> |
||||
|
</template> |
||||
|
</div> |
||||
|
<div class="form-item-bottom"> |
||||
|
<template > |
||||
|
<slot name="formDom"></slot> |
||||
|
</template> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'GuipFormItem', |
||||
|
props:['label','required','addClass','column'], |
||||
|
data() { |
||||
|
return { |
||||
|
hasError: false, |
||||
|
// 目前这两个宽度用的最多,其余宽度自定义类名修改吧 |
||||
|
classList:{ |
||||
|
'w510':'w510', |
||||
|
'w388':'w388' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
// dynamicClasses() { |
||||
|
// return { |
||||
|
// active: this.isActive, // 如果isActive为true,则添加'active'类 |
||||
|
// error: this.hasError, // 如果hasError为true,则添加'error'类 |
||||
|
// highlighted: this.isHighlighted, // 如果isHighlighted为true,则添加'highlighted'类 |
||||
|
// }; |
||||
|
// } |
||||
|
}, |
||||
|
mounted(){ |
||||
|
// console.log(this.required,'required----'); |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style lang="scss" scoped> |
||||
|
|
||||
|
</style> |
||||
@ -0,0 +1,170 @@ |
|||||
|
<template> |
||||
|
<transition name="fade"> |
||||
|
<div v-if="visible" class="custom-message" :class="[type, position]"> |
||||
|
<img v-if="showImage" :src="imageUrl" class="message-image" /> |
||||
|
<i v-else :class="iconClass"></i> |
||||
|
<span class="message-content">{{ message }}</span> |
||||
|
</div> |
||||
|
</transition> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'CustomMessage', |
||||
|
props: { |
||||
|
type: { |
||||
|
type: String, |
||||
|
default: 'info', |
||||
|
validator: value => ['success', 'warning', 'error', 'info'].includes(value) |
||||
|
}, |
||||
|
message: { |
||||
|
type: String, |
||||
|
required: true |
||||
|
}, |
||||
|
duration: { |
||||
|
type: Number, |
||||
|
default: 3000 |
||||
|
}, |
||||
|
position: { |
||||
|
type: String, |
||||
|
default: 'top-center', |
||||
|
validator: value => ['top-center', 'top-right', 'top-left', 'bottom-center', 'bottom-right', 'bottom-left'].includes(value) |
||||
|
}, |
||||
|
showImage: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
}, |
||||
|
imageUrl: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
}, |
||||
|
iconClass: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
visible: false |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.visible = true |
||||
|
this.startTimer() |
||||
|
}, |
||||
|
methods: { |
||||
|
startTimer() { |
||||
|
if (this.duration > 0) { |
||||
|
setTimeout(() => { |
||||
|
this.close() |
||||
|
}, this.duration) |
||||
|
} |
||||
|
}, |
||||
|
close() { |
||||
|
this.visible = false |
||||
|
setTimeout(() => { |
||||
|
this.$destroy() |
||||
|
this.$el.parentNode.removeChild(this.$el) |
||||
|
}, 300) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
.custom-message { |
||||
|
position: fixed; |
||||
|
z-index: 9999; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 14px 21px; |
||||
|
transition: all 0.3s; |
||||
|
font-size: 14px; |
||||
|
font-weight: normal; |
||||
|
line-height: normal; |
||||
|
letter-spacing: 0.08em; |
||||
|
color: #626573; |
||||
|
border-radius: 4px; |
||||
|
background: #FFFFFF; |
||||
|
/* 阴影/低阴影 */ |
||||
|
box-shadow: 0px 3px 8px 0px rgba(0, 0, 0, 0.16); |
||||
|
} |
||||
|
|
||||
|
/* 位置样式 */ |
||||
|
.top-center { |
||||
|
top: 20px; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
} |
||||
|
.top-right { |
||||
|
top: 20px; |
||||
|
right: 20px; |
||||
|
} |
||||
|
.top-left { |
||||
|
top: 20px; |
||||
|
left: 20px; |
||||
|
} |
||||
|
.bottom-center { |
||||
|
bottom: 20px; |
||||
|
left: 50%; |
||||
|
transform: translateX(-50%); |
||||
|
} |
||||
|
.bottom-right { |
||||
|
bottom: 20px; |
||||
|
right: 20px; |
||||
|
} |
||||
|
.bottom-left { |
||||
|
bottom: 20px; |
||||
|
left: 20px; |
||||
|
} |
||||
|
|
||||
|
/* 类型样式 */ |
||||
|
/* .success { |
||||
|
background-color: #f6ffed; |
||||
|
border: 1px solid #b7eb8f; |
||||
|
color: #52c41a; |
||||
|
} |
||||
|
.info { |
||||
|
background-color: #e6f7ff; |
||||
|
border: 1px solid #91d5ff; |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
.warning { |
||||
|
background-color: #fffbe6; |
||||
|
border: 1px solid #ffe58f; |
||||
|
color: #faad14; |
||||
|
} |
||||
|
.error { |
||||
|
background-color: #fff2f0; |
||||
|
border: 1px solid #ffccc7; |
||||
|
color: #f5222d; |
||||
|
} */ |
||||
|
|
||||
|
.message-image { |
||||
|
width: 18px; |
||||
|
height: 18px; |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
|
||||
|
/* 动画效果 */ |
||||
|
.fade-enter-active, .fade-leave-active { |
||||
|
transition: opacity 0.3s, transform 0.3s; |
||||
|
} |
||||
|
.fade-enter, .fade-leave-to { |
||||
|
opacity: 0; |
||||
|
} |
||||
|
.fade-enter.top-center, .fade-leave-to.top-center { |
||||
|
transform: translate(-50%, -20px); |
||||
|
} |
||||
|
.fade-enter.top-right, .fade-leave-to.top-right, |
||||
|
.fade-enter.top-left, .fade-leave-to.top-left { |
||||
|
transform: translateY(-20px); |
||||
|
} |
||||
|
.fade-enter.bottom-center, .fade-leave-to.bottom-center { |
||||
|
transform: translate(-50%, 20px); |
||||
|
} |
||||
|
.fade-enter.bottom-right, .fade-leave-to.bottom-right, |
||||
|
.fade-enter.bottom-left, .fade-leave-to.bottom-left { |
||||
|
transform: translateY(20px); |
||||
|
} |
||||
|
</style> |
||||
@ -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 } |
||||
|
Before Width: | Height: | Size: 673 B After Width: | Height: | Size: 297 B |
|
After Width: | Height: | Size: 802 B |
|
After Width: | Height: | Size: 654 B |
|
After Width: | Height: | Size: 746 B |
@ -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<boolean>} 是否复制成功 |
||||
|
*/ |
||||
|
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<boolean>} 是否复制成功 |
||||
|
*/ |
||||
|
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; |
||||
@ -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 + "字符"; |
||||
|
} |
||||
|
|
||||
@ -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); |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}; |
||||
@ -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 |
||||
@ -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', |
||||
|
} |
||||
|
}) |
||||
|
]) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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; |
||||
Loading…
Reference in new issue