diff --git a/src/components/chooseImg/index.vue b/src/components/chooseImg/index.vue new file mode 100644 index 0000000..cccd5db --- /dev/null +++ b/src/components/chooseImg/index.vue @@ -0,0 +1,222 @@ + + + + + diff --git a/src/components/commandMenu/index.vue b/src/components/commandMenu/index.vue new file mode 100644 index 0000000..3389de0 --- /dev/null +++ b/src/components/commandMenu/index.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/src/utils/bus.js b/src/utils/bus.js new file mode 100644 index 0000000..4b673fa --- /dev/null +++ b/src/utils/bus.js @@ -0,0 +1,6 @@ + +// using ES6 modules +import mitt from 'mitt' + +export const emitter = mitt() + diff --git a/src/utils/closeThisPage.js b/src/utils/closeThisPage.js new file mode 100644 index 0000000..b2a0c05 --- /dev/null +++ b/src/utils/closeThisPage.js @@ -0,0 +1,5 @@ +import { emitter } from '@/utils/bus.js' + +export const closeThisPage = () => { + emitter.emit('closeThisPage') +} diff --git a/src/utils/date.js b/src/utils/date.js new file mode 100644 index 0000000..6bb8570 --- /dev/null +++ b/src/utils/date.js @@ -0,0 +1,30 @@ +// 对Date的扩展,将 Date 转化为指定格式的String +// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符, +// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字) +// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 +// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18 +// eslint-disable-next-line no-extend-native +Date.prototype.Format = function(fmt) { + var o = { + 'M+': this.getMonth() + 1, // 月份 + 'd+': this.getDate(), // 日 + 'h+': this.getHours(), // 小时 + 'm+': this.getMinutes(), // 分 + 's+': this.getSeconds(), // 秒 + 'q+': Math.floor((this.getMonth() + 3) / 3), // 季度 + 'S': this.getMilliseconds() // 毫秒 + } + if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)) } + for (var k in o) { + if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) } + } + return fmt +} + +export function formatTimeToStr(times, pattern) { + var d = new Date(times).Format('yyyy-MM-dd hh:mm:ss') + if (pattern) { + d = new Date(times).Format(pattern) + } + return d.toLocaleString() +} diff --git a/src/utils/dictionary.js b/src/utils/dictionary.js new file mode 100644 index 0000000..70ea9ce --- /dev/null +++ b/src/utils/dictionary.js @@ -0,0 +1,26 @@ +import { useDictionaryStore } from '@/pinia/modules/dictionary' +// 获取字典方法 使用示例 getDict('sex').then(res) 或者 async函数下 const res = await getDict('sex') +export const getDict = async(type) => { + const dictionaryStore = useDictionaryStore() + await dictionaryStore.getDictionary(type) + return dictionaryStore.dictionaryMap[type] +} + +// 字典文字展示方法 +export const showDictLabel = ( + dict, + code, + keyCode = 'value', + valueCode = 'label' +) => { + if (!dict) { + return '' + } + const dictMap = {} + dict.forEach(item => { + if (Reflect.has(item, keyCode) && Reflect.has(item, valueCode)) { + dictMap[item[keyCode]] = item[valueCode] + } + }) + return Reflect.has(dictMap, code) ? dictMap[code] : '' +} diff --git a/src/utils/doc.js b/src/utils/doc.js new file mode 100644 index 0000000..55a3949 --- /dev/null +++ b/src/utils/doc.js @@ -0,0 +1,3 @@ +export const toDoc = (url) => { + window.open(url, '_blank') +} diff --git a/src/utils/downloadImg.js b/src/utils/downloadImg.js new file mode 100644 index 0000000..93fb222 --- /dev/null +++ b/src/utils/downloadImg.js @@ -0,0 +1,19 @@ +export const downloadImage = (imgsrc, name) => { // 下载图片地址和图片名 + var image = new Image() + image.setAttribute('crossOrigin', 'anonymous') + image.onload = function() { + var canvas = document.createElement('canvas') + canvas.width = image.width + canvas.height = image.height + var context = canvas.getContext('2d') + context.drawImage(image, 0, 0, image.width, image.height) + var url = canvas.toDataURL('image/png') // 得到图片的base64编码数据 + + var a = document.createElement('a') // 生成一个a元素 + var event = new MouseEvent('click') // 创建一个单击事件 + a.download = name || 'photo' // 设置图片名称 + a.href = url // 将生成的URL设置为a.href属性 + a.dispatchEvent(event) // 触发a的单击事件 + } + image.src = imgsrc +} diff --git a/src/utils/fmtRouterTitle.js b/src/utils/fmtRouterTitle.js new file mode 100644 index 0000000..bcaeb67 --- /dev/null +++ b/src/utils/fmtRouterTitle.js @@ -0,0 +1,13 @@ +export const fmtTitle = (title, now) => { + const reg = /\$\{(.+?)\}/ + const reg_g = /\$\{(.+?)\}/g + const result = title.match(reg_g) + if (result) { + result.forEach((item) => { + const key = item.match(reg)[1] + const value = now.params[key] || now.query[key] + title = title.replace(item, value) + }) + } + return title +} diff --git a/src/utils/format.js b/src/utils/format.js new file mode 100644 index 0000000..b052ac9 --- /dev/null +++ b/src/utils/format.js @@ -0,0 +1,67 @@ +import { formatTimeToStr } from '@/utils/date' +import { getDict } from '@/utils/dictionary' + +export const formatBoolean = (bool) => { + if (bool !== null) { + return bool ? '开启' : '关闭' + } else { + return '' + } +} +export const formatDate = (time) => { + if (time !== null && time !== '') { + var date = new Date(time) + return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss') + } else { + return '' + } +} +export const formatOnlyDate = (time) => { + if (time !== null && time !== '') { + var date = new Date(time) + return formatTimeToStr(date, 'yyyy-MM-dd') + } else { + return '' + } +} +export const formatPriceType = (priceType) => { + switch (priceType) { + case 1: return '出厂价' + default: '未定义' + } +} + +export const filterDict = (value, options) => { + const rowLabel = options && options.filter(item => item.value === value) + return rowLabel && rowLabel[0] && rowLabel[0].label +} + +export const getDictFunc = async (type) => { + const dicts = await getDict(type) + return dicts +} + +const path = import.meta.env.VITE_BASE_PATH + ':' + import.meta.env.VITE_SERVER_PORT + '/' +export const ReturnArrImg = (arr) => { + const imgArr = [] + if (arr instanceof Array) { // 如果是数组类型 + for (const arrKey in arr) { + if (arr[arrKey].slice(0, 4) !== 'http') { + imgArr.push(path + arr[arrKey]) + } else { + imgArr.push(arr[arrKey]) + } + } + } else { // 如果不是数组类型 + if (arr.slice(0, 4) !== 'http') { + imgArr.push(path + arr) + } else { + imgArr.push(arr) + } + } + return imgArr +} + +export const onDownloadFile = (url) => { + window.open(path + url) +} diff --git a/src/utils/image.js b/src/utils/image.js new file mode 100644 index 0000000..0111b81 --- /dev/null +++ b/src/utils/image.js @@ -0,0 +1,101 @@ +export default class ImageCompress { + constructor(file, fileSize, maxWH = 1920) { + this.file = file + this.fileSize = fileSize + this.maxWH = maxWH // 最大长宽 + } + + compress() { + // 压缩 + const fileType = this.file.type + const fileSize = this.file.size / 1024 + return new Promise(resolve => { + const reader = new FileReader() + reader.readAsDataURL(this.file) + reader.onload = () => { + const canvas = document.createElement('canvas') + const img = document.createElement('img') + img.src = reader.result + img.onload = () => { + const ctx = canvas.getContext('2d') + const _dWH = this.dWH(img.width, img.height, this.maxWH) + canvas.width = _dWH.width + canvas.height = _dWH.height + + // 清空后, 重写画布 + ctx.clearRect(0, 0, canvas.width, canvas.height) + ctx.drawImage(img, 0, 0, canvas.width, canvas.height) + + const newImgData = canvas.toDataURL(fileType, 0.90) + + // 压缩宽高后的图像大小 + const newImgSize = this.fileSizeKB(newImgData) + + if (newImgSize > this.fileSize) { + console.log('图片尺寸太大!' + fileSize + ' >> ' + newImgSize) + } + + const blob = this.dataURLtoBlob(newImgData, fileType) + const nfile = new File([blob], this.file.name) + resolve(nfile) + } + } + }) + } + + /** + * 长宽等比缩小 + * 图像的一边(长或宽)为最大目标值 + */ + dWH(srcW, srcH, dMax) { + const defaults = { + width: srcW, + height: srcH + } + if (Math.max(srcW, srcH) > dMax) { + if (srcW > srcH) { + defaults.width = dMax + defaults.height = Math.round(srcH * (dMax / srcW)) + return defaults + } else { + defaults.height = dMax + defaults.width = Math.round(srcW * (dMax / srcH)) + return defaults + } + } else { + return defaults + } + } + + fileSizeKB(dataURL) { + let sizeKB = 0 + sizeKB = Math.round((dataURL.split(',')[1].length * 3 / 4) / 1024) + return sizeKB + } + + /** + * 转为Blob + */ + dataURLtoBlob(dataURL, fileType) { + const byteString = atob(dataURL.split(',')[1]) + let mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0] + const ab = new ArrayBuffer(byteString.length) + const ia = new Uint8Array(ab) + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i) + } + if (fileType) { + mimeString = fileType + } + return new Blob([ab], { type: mimeString, lastModifiedDate: new Date() }) + } +} + +const path = import.meta.env.VITE_FILE_API + '/' +export const getUrl = (url) => url && url.slice(0, 4) !== 'http' ? path + url : url + +export const isVideoExt = (url) => url.endsWith('.mp4') || url.endsWith('.mov') || url.endsWith('.webm') || url.endsWith('.ogg'); + +export const isVideoMime = (type) => type == 'video/mp4' || type == 'video/webm' || type == 'video/ogg'; + +export const isImageMime = (type) => type == 'image/jpeg' || type == 'image/png' || type == 'image/webp' || type == 'image/svg+xml'; diff --git a/src/utils/page.js b/src/utils/page.js new file mode 100644 index 0000000..6a3c6d8 --- /dev/null +++ b/src/utils/page.js @@ -0,0 +1,9 @@ +import { fmtTitle } from '@/utils/fmtRouterTitle' +import config from '@/core/config' +export default function getPageTitle(pageTitle, route) { + if (pageTitle) { + const title = fmtTitle(pageTitle, route) + return `${title} - ${config.appName}` + } + return `${config.appName}` +} diff --git a/src/utils/positionToCode.js b/src/utils/positionToCode.js new file mode 100644 index 0000000..de24931 --- /dev/null +++ b/src/utils/positionToCode.js @@ -0,0 +1,36 @@ +export const initDom = () => { + if (import.meta.env.MODE === 'development') { + document.onmousedown = function(e) { + if (e.shiftKey && e.altKey && e.button === 0) { + e.preventDefault() + sendRequestToOpenFileInEditor(getFilePath(e)) + } + } + } +} + +const getFilePath = (e) => { + let element = e + if (e.target) { + element = e.target + } + if (!element || !element.getAttribute) return null + if (element.getAttribute('code-location')) { + return element.getAttribute('code-location') + } + return getFilePath(element.parentNode) +} + +const sendRequestToOpenFileInEditor = (filePath) => { + const protocol = window.location.protocol + ? window.location.protocol + : 'http:' + const hostname = window.location.hostname + ? window.location.hostname + : 'localhost' + const port = window.location.port ? window.location.port : '80' + fetch(`${protocol}//${hostname}:${port}/gvaPositionCode?filePath=${filePath}`) + .catch((error) => { + console.log(error) + }) +} diff --git a/src/utils/request.js b/src/utils/request.js new file mode 100644 index 0000000..3625ac1 --- /dev/null +++ b/src/utils/request.js @@ -0,0 +1,145 @@ +import axios from 'axios' // 引入axios +import { ElMessage, ElMessageBox } from 'element-plus' +import { useUserStore } from '@/pinia/modules/user' +import router from '@/router/index' +import { ElLoading } from 'element-plus' + +const service = axios.create({ + baseURL: import.meta.env.VITE_BASE_API, + timeout: 99999 +}) +let activeAxios = 0 +let timer +let loadingInstance +const showLoading = (option = { + target: null, +}) => { + const loadDom = document.getElementById('gva-base-load-dom') + activeAxios++ + if (timer) { + clearTimeout(timer) + } + timer = setTimeout(() => { + if (activeAxios > 0) { + if (!option.target) option.target = loadDom + loadingInstance = ElLoading.service(option) + } + }, 400) +} + +const closeLoading = () => { + activeAxios-- + if (activeAxios <= 0) { + clearTimeout(timer) + loadingInstance && loadingInstance.close() + } +} +// http request 拦截器 +service.interceptors.request.use( + config => { + if (!config.donNotShowLoading) { + showLoading(config.loadingOption) + } + const userStore = useUserStore() + config.headers = { + 'Content-Type': 'application/json', + 'x-token': userStore.token, + 'x-user-id': userStore.userInfo.ID, + ...config.headers + } + return config + }, + error => { + if (!error.config.donNotShowLoading) { + closeLoading() + } + ElMessage({ + showClose: true, + message: error, + type: 'error' + }) + return error + } +) + +// http response 拦截器 +service.interceptors.response.use( + response => { + const userStore = useUserStore() + if (!response.config.donNotShowLoading) { + closeLoading() + } + if (response.headers['new-token']) { + userStore.setToken(response.headers['new-token']) + } + if (response.data.code === 0 || response.headers.success === 'true') { + if (response.headers.msg) { + response.data.msg = decodeURI(response.headers.msg) + } + return response.data + } else { + ElMessage({ + showClose: true, + message: response.data.msg || decodeURI(response.headers.msg), + type: 'error' + }) + if (response.data.data && response.data.data.reload) { + userStore.token = '' + window.localStorage.removeItem('token') + router.push({ name: 'Login', replace: true }) + } + return response.data.msg ? response.data : response + } + }, + error => { + if (!error.config.donNotShowLoading) { + closeLoading() + } + + if (!error.response) { + ElMessageBox.confirm(` +

检测到请求错误

+

${error}

+ `, '请求报错', { + dangerouslyUseHTMLString: true, + distinguishCancelAndClose: true, + confirmButtonText: '稍后重试', + cancelButtonText: '取消' + }) + return + } + + switch (error.response.status) { + case 500: + ElMessageBox.confirm(` +

检测到接口错误${error}

+

错误码 500 :此类错误内容常见于后台panic,请先查看后台日志,如果影响您正常使用可强制登出清理缓存

+ `, '接口报错', { + dangerouslyUseHTMLString: true, + distinguishCancelAndClose: true, + confirmButtonText: '清理缓存', + cancelButtonText: '取消' + }) + .then(() => { + const userStore = useUserStore() + userStore.ClearStorage() + router.push({ name: 'Login', replace: true }) + }) + break + case 404: + ElMessageBox.confirm(` +

检测到接口错误${error}

+

错误码 404 :此类错误多为接口未注册(或未重启)或者请求路径(方法)与api路径(方法)不符--如果为自动化代码请检查是否存在空格

+ `, '接口报错', { + dangerouslyUseHTMLString: true, + distinguishCancelAndClose: true, + confirmButtonText: '我知道了', + cancelButtonText: '取消' + }) + break + } + + return error + } +) +export default service diff --git a/src/utils/stringFun.js b/src/utils/stringFun.js new file mode 100644 index 0000000..eac4179 --- /dev/null +++ b/src/utils/stringFun.js @@ -0,0 +1,29 @@ +/* eslint-disable */ +export const toUpperCase = (str) => { + if (str[0]) { + return str.replace(str[0], str[0].toUpperCase()) + } else { + return '' + } +} + +export const toLowerCase = (str) => { + if (str[0]) { + return str.replace(str[0], str[0].toLowerCase()) + } else { + return '' + } +} + +// 驼峰转换下划线 +export const toSQLLine = (str) => { + if (str === 'ID') return 'ID' + return str.replace(/([A-Z])/g, "_$1").toLowerCase(); +} + +// 下划线转换驼峰 +export const toHump = (name) => { + return name.replace(/\_(\w)/g, function(all, letter) { + return letter.toUpperCase(); + }); +} \ No newline at end of file diff --git a/src/view/about/index.vue b/src/view/about/index.vue new file mode 100644 index 0000000..1c858b1 --- /dev/null +++ b/src/view/about/index.vue @@ -0,0 +1,17 @@ + + + diff --git a/src/view/companyPrice/companyPrice.vue b/src/view/companyPrice/companyPrice.vue new file mode 100755 index 0000000..f9e4655 --- /dev/null +++ b/src/view/companyPrice/companyPrice.vue @@ -0,0 +1,458 @@ + + + + + diff --git a/src/view/companyPrice/companyPriceForm.vue b/src/view/companyPrice/companyPriceForm.vue new file mode 100755 index 0000000..2844783 --- /dev/null +++ b/src/view/companyPrice/companyPriceForm.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/src/view/crawl100ppi/crawl100ppi.vue b/src/view/crawl100ppi/crawl100ppi.vue new file mode 100755 index 0000000..2fc72af --- /dev/null +++ b/src/view/crawl100ppi/crawl100ppi.vue @@ -0,0 +1,581 @@ + + + + + diff --git a/src/view/crawl100ppi/crawl100ppiForm.vue b/src/view/crawl100ppi/crawl100ppiForm.vue new file mode 100755 index 0000000..4145034 --- /dev/null +++ b/src/view/crawl100ppi/crawl100ppiForm.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/src/view/crawlFieldReplace/crawlFieldReplace.vue b/src/view/crawlFieldReplace/crawlFieldReplace.vue new file mode 100755 index 0000000..cb041e2 --- /dev/null +++ b/src/view/crawlFieldReplace/crawlFieldReplace.vue @@ -0,0 +1,409 @@ + + + + + diff --git a/src/view/crawlFieldReplace/crawlFieldReplaceForm.vue b/src/view/crawlFieldReplace/crawlFieldReplaceForm.vue new file mode 100755 index 0000000..84c19e2 --- /dev/null +++ b/src/view/crawlFieldReplace/crawlFieldReplaceForm.vue @@ -0,0 +1,128 @@ + + + + + +@/api/crawlFieldReplace \ No newline at end of file diff --git a/src/view/dashboard/dashboardCharts/echartsLine.vue b/src/view/dashboard/dashboardCharts/echartsLine.vue new file mode 100644 index 0000000..66e1c8c --- /dev/null +++ b/src/view/dashboard/dashboardCharts/echartsLine.vue @@ -0,0 +1,138 @@ + + + diff --git a/src/view/dashboard/dashboardTable/dashboardTable.vue b/src/view/dashboard/dashboardTable/dashboardTable.vue new file mode 100644 index 0000000..8e3e430 --- /dev/null +++ b/src/view/dashboard/dashboardTable/dashboardTable.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/view/dashboard/index.vue b/src/view/dashboard/index.vue new file mode 100644 index 0000000..a92d8f9 --- /dev/null +++ b/src/view/dashboard/index.vue @@ -0,0 +1,210 @@ + + + + + diff --git a/src/view/dashboard/weather.js b/src/view/dashboard/weather.js new file mode 100644 index 0000000..e0d88fd --- /dev/null +++ b/src/view/dashboard/weather.js @@ -0,0 +1,35 @@ + +import axios from 'axios' +import { ref } from 'vue' + +const weatherInfo = ref('今日晴,0℃ - 10℃,天气寒冷,注意添加衣物。') +const amapKey = '1f0c8b27920dc41d204800793d629d8e' + +export const useWeatherInfo = () => { + ip() + return weatherInfo +} + +export const ip = async () => { + // key换成你自己的 https://console.amap.com/dev/index + if (amapKey === '') { + return false + } + const res = await axios.get('https://restapi.amap.com/v3/ip?key=' + amapKey) + var cityCode + if (res.data.status !== '0') { + cityCode = res.data.adcode + } else { + cityCode = '100000' + } + getWeather(cityCode) +} + +const getWeather = async (code) => { + const url = 'https://restapi.amap.com/v3/weather/weatherInfo?key=' + amapKey + '&extensions=base&city=' + code + const response = await axios.get(url) + if (response.data.status === '1') { + const s = response.data.lives[0] + weatherInfo.value = s.city + ' 天气:' + s.weather + ' 温度:' + s.temperature + '摄氏度 风向:' + s.winddirection + ' 风力:' + s.windpower + '级 空气湿度:' + s.humidity + } +} diff --git a/src/view/error/index.vue b/src/view/error/index.vue new file mode 100644 index 0000000..9a0b6b9 --- /dev/null +++ b/src/view/error/index.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/view/error/reload.vue b/src/view/error/reload.vue new file mode 100644 index 0000000..2504c55 --- /dev/null +++ b/src/view/error/reload.vue @@ -0,0 +1,14 @@ + + + diff --git a/src/view/example/breakpoint/breakpoint.vue b/src/view/example/breakpoint/breakpoint.vue new file mode 100644 index 0000000..092ee76 --- /dev/null +++ b/src/view/example/breakpoint/breakpoint.vue @@ -0,0 +1,291 @@ + + + + + diff --git a/src/view/example/customer/customer.vue b/src/view/example/customer/customer.vue new file mode 100644 index 0000000..fda75ee --- /dev/null +++ b/src/view/example/customer/customer.vue @@ -0,0 +1,232 @@ + + + + + diff --git a/src/view/example/index.vue b/src/view/example/index.vue new file mode 100644 index 0000000..8b322d6 --- /dev/null +++ b/src/view/example/index.vue @@ -0,0 +1,22 @@ + + + diff --git a/src/view/example/upload/upload.vue b/src/view/example/upload/upload.vue new file mode 100644 index 0000000..8ffe123 --- /dev/null +++ b/src/view/example/upload/upload.vue @@ -0,0 +1,247 @@ + + + + + diff --git a/src/view/init/index.vue b/src/view/init/index.vue new file mode 100644 index 0000000..5478d4a --- /dev/null +++ b/src/view/init/index.vue @@ -0,0 +1,361 @@ + + + + + diff --git a/src/view/layout/aside/index.vue b/src/view/layout/aside/index.vue new file mode 100644 index 0000000..22860eb --- /dev/null +++ b/src/view/layout/aside/index.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/src/view/layout/index.vue b/src/view/layout/index.vue new file mode 100644 index 0000000..65a8c9d --- /dev/null +++ b/src/view/layout/index.vue @@ -0,0 +1,374 @@ + + + + + diff --git a/src/view/routerHolder.vue b/src/view/routerHolder.vue new file mode 100644 index 0000000..da4e5fb --- /dev/null +++ b/src/view/routerHolder.vue @@ -0,0 +1,25 @@ + + + +