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