Merge branch 'master' of https://github.com/zouzhibin/vue-admin-perfect into vue-i18n
Conflicts: src/main.ts
This commit is contained in:
commit
b864ce1b0d
|
|
@ -2,4 +2,4 @@
|
|||
NODE_ENV = 'development'
|
||||
|
||||
# 本地环境接口地址
|
||||
VITE_API_URL = '/api'
|
||||
VUE_APP_BASE_API = '/api'
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
# 线上环境
|
||||
NODE_ENV = "production"
|
||||
|
||||
# 线上环境接口地址
|
||||
VUE_APP_BASE_API = '/api'
|
||||
|
|
|
|||
59
index.html
59
index.html
|
|
@ -7,7 +7,64 @@
|
|||
<title>Vite + Vue + TS</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="app">
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.init-loading-wrap{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.init-loading-inner {
|
||||
width: 20px;
|
||||
height: 50px;
|
||||
background: #1890ff;
|
||||
float: left;
|
||||
margin: 0 3px;
|
||||
animation: init-loading-inner linear 1s infinite;
|
||||
-webkit-animation: init-loading-inner linear 1s infinite;
|
||||
}
|
||||
.init-loading-inner:nth-child(1){
|
||||
animation-delay:0s;
|
||||
}
|
||||
.init-loading-inner:nth-child(2){
|
||||
animation-delay:0.15s;
|
||||
}
|
||||
.init-loading-inner:nth-child(3){
|
||||
animation-delay:0.3s;
|
||||
}
|
||||
.init-loading-inner:nth-child(4){
|
||||
animation-delay:0.45s;
|
||||
}
|
||||
.init-loading-inner:nth-child(5){
|
||||
animation-delay:0.6s;
|
||||
}
|
||||
@keyframes init-loading-inner{
|
||||
0%,60%,100% {transform: scale(1);}
|
||||
30% {transform: scaleY(3);}
|
||||
}
|
||||
@-webkit-keyframes init-loading-inner{
|
||||
0%,60%,100% {transform: scale(1);}
|
||||
30% {transform: scaleY(3);}
|
||||
}
|
||||
</style>
|
||||
<div class="init-loading-wrap">
|
||||
<div class="init-loading-inner"></div>
|
||||
<div class="init-loading-inner"></div>
|
||||
<div class="init-loading-inner"></div>
|
||||
<div class="init-loading-inner"></div>
|
||||
<div class="init-loading-inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
"@vueuse/core": "^9.1.1",
|
||||
"@wangeditor/editor": "^5.1.14",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
"axios": "^0.27.2",
|
||||
"clipboard": "^2.0.10",
|
||||
"core-js": "^3.6.5",
|
||||
"dayjs": "^1.11.4",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
```
|
||||
export interface AxiosRequestConfig {
|
||||
// `url` 是用于请求的服务器 URL
|
||||
url?: string;
|
||||
|
||||
// `method` 是创建请求时使用的方法
|
||||
method?: Method;
|
||||
|
||||
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
|
||||
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
|
||||
baseURL?: string;
|
||||
|
||||
// `transformRequest` 允许在向服务器发送前,修改请求数据
|
||||
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
|
||||
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
|
||||
transformRequest?: AxiosTransformer | AxiosTransformer[];
|
||||
|
||||
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
|
||||
transformResponse?: AxiosTransformer | AxiosTransformer[];
|
||||
|
||||
// `headers` 是即将被发送的自定义请求头
|
||||
headers?: any;
|
||||
|
||||
// `params` 是即将与请求一起发送的 URL 参数
|
||||
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
|
||||
params?: any;
|
||||
|
||||
// `paramsSerializer` 是一个负责 `params` 序列化的函数
|
||||
paramsSerializer?: (params: any) => string;
|
||||
|
||||
// `data` 是作为请求主体被发送的数据
|
||||
// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
|
||||
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
|
||||
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
|
||||
// - 浏览器专属:FormData, File, Blob
|
||||
// - Node 专属: Stream
|
||||
data?: any;
|
||||
|
||||
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
|
||||
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
|
||||
timeout?: number;
|
||||
|
||||
// 超时提示消息
|
||||
timeoutErrorMessage?: string;
|
||||
|
||||
// `withCredentials` 表示跨域请求时是否需要使用凭证
|
||||
withCredentials?: boolean;
|
||||
|
||||
// `adapter` 允许自定义处理请求,以使测试更轻松
|
||||
adapter?: AxiosAdapter;
|
||||
|
||||
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
|
||||
auth?: AxiosBasicCredentials;
|
||||
|
||||
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
|
||||
responseType?: ResponseType;
|
||||
|
||||
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
|
||||
xsrfCookieName?: string;
|
||||
|
||||
// `xsrfHeaderName` 是携带 xsrf 令牌值的 http 标头的名称
|
||||
xsrfHeaderName?: string;
|
||||
|
||||
// `onUploadProgress` 允许为上传处理进度事件
|
||||
onUploadProgress?: (progressEvent: any) => void;
|
||||
|
||||
// `onDownloadProgress` 允许为下载处理进度事件
|
||||
onDownloadProgress?: (progressEvent: any) => void;
|
||||
|
||||
// `maxContentLength` 定义允许的响应内容的最大尺寸
|
||||
maxContentLength?: number;
|
||||
|
||||
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。
|
||||
// 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),
|
||||
// promise 将被 resolve; 否则,promise 将被 rejecte
|
||||
validateStatus?: ((status: number) => boolean) | null;
|
||||
|
||||
// 请求体最大尺寸
|
||||
maxBodyLength?: number;
|
||||
|
||||
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
|
||||
// 如果设置为0,将不会 follow 任何重定向
|
||||
maxRedirects?: number;
|
||||
|
||||
// `socketPath` 定义了一个在 node.js 中使用的 UNIX Socket。
|
||||
// 只能指定 `socketPath` 或 `proxy`。
|
||||
// 如果两者都指定,则使用 `socketPath`。
|
||||
socketPath?: string | null;
|
||||
|
||||
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。
|
||||
httpAgent?: any;
|
||||
httpsAgent?: any;
|
||||
|
||||
// 'proxy' 定义代理服务器的主机名称和端口
|
||||
proxy?: AxiosProxyConfig | false;
|
||||
|
||||
// `cancelToken` 指定用于取消请求的 cancel token
|
||||
cancelToken?: CancelToken;
|
||||
|
||||
// 将其设置为`false`,它将不会解压缩您的响应,而是保留原始的Content-Encoding头。
|
||||
// 默认是true
|
||||
decompress?: boolean;
|
||||
|
||||
// 控制响应数据是否转换
|
||||
transitional?: TransitionalOptions
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
export const errorCodeType = function(code:string):string{
|
||||
let errMessage:string = "未知错误"
|
||||
switch (code) {
|
||||
case 400:
|
||||
errMessage = '请求失败!请您稍后重试'
|
||||
break
|
||||
case 401:
|
||||
errMessage = '未授权,请重新登录'
|
||||
break
|
||||
case 403:
|
||||
errMessage = '当前账号无权限访问!'
|
||||
break
|
||||
case 404:
|
||||
errMessage = '你所访问的资源不存在!'
|
||||
break
|
||||
case 405:
|
||||
errMessage = '请求方式错误!请您稍后重试'
|
||||
break
|
||||
case 408:
|
||||
errMessage = '请求超时!请您稍后重试'
|
||||
break
|
||||
case 500:
|
||||
errMessage = '服务器端出错'
|
||||
break
|
||||
case 501:
|
||||
errMessage = '网络未实现'
|
||||
break
|
||||
case 502:
|
||||
errMessage = '网络错误'
|
||||
break
|
||||
case 503:
|
||||
errMessage = '服务不可用'
|
||||
break
|
||||
case 504:
|
||||
errMessage = '网络超时'
|
||||
break
|
||||
case 505:
|
||||
errMessage = 'http版本不支持该请求'
|
||||
break
|
||||
default:
|
||||
errMessage = `其他连接错误 --${code}`
|
||||
}
|
||||
return errMessage
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
import axios, { AxiosInstance, AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||||
import { ElMessage } from "element-plus";
|
||||
import {useUserStore} from "@/store/modules/user"
|
||||
// 创建axios实例 进行基本参数配置
|
||||
const service = axios.create({
|
||||
// 默认请求地址,根据环境的不同可在.env 文件中进行修改
|
||||
baseURL: import.meta.env.VUE_APP_BASE_API,
|
||||
// 设置接口访问超时时间
|
||||
timeout: 3000000, // request timeout,
|
||||
// 跨域时候允许携带凭证
|
||||
withCredentials: true
|
||||
})
|
||||
|
||||
// request interceptor 接口请求拦截
|
||||
service.interceptors.request.use((config:AxiosRequestConfig)=>{
|
||||
/**
|
||||
* 用户登录之后获取服务端返回的token,后面每次请求都在请求头中带上token进行JWT校验
|
||||
* token 存储在本地储存中(storage)、vuex、pinia
|
||||
*/
|
||||
const userStore = useUserStore();
|
||||
const token: string = userStore.token;
|
||||
// 自定义请求头
|
||||
if(token){ config.headers['Authorization'] = token}
|
||||
return config
|
||||
},(error: AxiosError) => {
|
||||
// 请求错误,这里可以用全局提示框进行提示
|
||||
return Promise.reject(error);
|
||||
})
|
||||
|
||||
// response interceptor 接口响应拦截
|
||||
service.interceptors.response.use((response: AxiosResponse) =>{
|
||||
// 直接返回res,当然你也可以只返回res.data
|
||||
// 系统如果有自定义code也可以在这里处理
|
||||
return response
|
||||
|
||||
|
||||
},(error: AxiosError) => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @description 显示错误消息
|
||||
* opt 传入参数
|
||||
* err 错误信息
|
||||
* type 消息类型
|
||||
* duration 消息持续时间
|
||||
*/
|
||||
function showErrMessage (opt, err, type:any= 'error', duration:number = 5000){
|
||||
ElMessage({
|
||||
message: err.msg,
|
||||
type:type,
|
||||
duration: duration
|
||||
})
|
||||
}
|
||||
|
||||
export default service
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import request from './request'
|
||||
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: '/vue-element-perfect/user/login',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
|
@ -11,13 +11,14 @@ import 'virtual:svg-icons-register'
|
|||
import SvgIcon from '@/components/SvgIcon/index.vue'// svg component
|
||||
// UI框架 element-plus
|
||||
import ElementPlus from 'element-plus'
|
||||
import UContainerLayout from '@/components/u-container-layout/index.vue'
|
||||
import 'element-plus/dist/index.css'
|
||||
|
||||
// 引入暗黑模式 element-plus 2.2 内置暗黑模式
|
||||
import 'element-plus/theme-chalk/dark/css-vars.css'
|
||||
// 自定义暗黑模式
|
||||
import "@/styles/element-dark.scss";
|
||||
|
||||
// 引入全局组件布局
|
||||
import UContainerLayout from '@/components/u-container-layout/index.vue'
|
||||
// i18n
|
||||
import I18n from "@/language/index";
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ export const useTagsViewStore = defineStore({
|
|||
delAllViews(){
|
||||
return new Promise((resolve) => {
|
||||
this.visitedViews = this.visitedViews.filter(v=>v.meta.affix)
|
||||
console.log('===============',this.visitedViews)
|
||||
this.cachedViews = this.visitedViews.filter(v=>v.meta.affix)
|
||||
resolve([...this.visitedViews])
|
||||
})
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ export const useUserStore = defineStore({
|
|||
},
|
||||
|
||||
},
|
||||
// 进行持久化存储
|
||||
persist: {
|
||||
// 本地存储的名称
|
||||
key: "userState",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
/* @Print.js
|
||||
* DH (http://denghao.me)
|
||||
* 2017-7-14
|
||||
*/
|
||||
(function (window, document) {
|
||||
var Print = function (dom, options) {
|
||||
if (!(this instanceof Print)) return new Print(dom, options);
|
||||
|
||||
this.options = this.extend({
|
||||
noPrint: '.no-print',
|
||||
onStart: function () { },
|
||||
onEnd: function () { }
|
||||
}, options);
|
||||
|
||||
if ((typeof dom) === "string") {
|
||||
this.dom = document.querySelector(dom);
|
||||
} else {
|
||||
this.dom = dom;
|
||||
}
|
||||
|
||||
this.init();
|
||||
};
|
||||
Print.prototype = {
|
||||
init: function () {
|
||||
var content = this.getStyle() + this.getHtml();
|
||||
this.writeIframe(content);
|
||||
},
|
||||
extend: function (obj, obj2) {
|
||||
for (var k in obj2) {
|
||||
obj[k] = obj2[k];
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
getStyle: function () {
|
||||
var str = "",
|
||||
styles = document.querySelectorAll('style,link');
|
||||
for (var i = 0; i < styles.length; i++) {
|
||||
str += styles[i].outerHTML;
|
||||
}
|
||||
str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
|
||||
|
||||
return str;
|
||||
},
|
||||
|
||||
getHtml: function () {
|
||||
var inputs = document.querySelectorAll('input');
|
||||
var textareas = document.querySelectorAll('textarea');
|
||||
var selects = document.querySelectorAll('select');
|
||||
|
||||
for (var k in inputs) {
|
||||
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
|
||||
if (inputs[k].checked == true) {
|
||||
inputs[k].setAttribute('checked', "checked")
|
||||
} else {
|
||||
inputs[k].removeAttribute('checked')
|
||||
}
|
||||
} else if (inputs[k].type == "text") {
|
||||
inputs[k].setAttribute('value', inputs[k].value)
|
||||
}
|
||||
}
|
||||
|
||||
for (var k2 in textareas) {
|
||||
if (textareas[k2].type == 'textarea') {
|
||||
textareas[k2].innerHTML = textareas[k2].value
|
||||
}
|
||||
}
|
||||
|
||||
for (var k3 in selects) {
|
||||
if (selects[k3].type == 'select-one') {
|
||||
var child = selects[k3].children;
|
||||
for (var i in child) {
|
||||
if (child[i].tagName == 'OPTION') {
|
||||
if (child[i].selected == true) {
|
||||
child[i].setAttribute('selected', "selected")
|
||||
} else {
|
||||
child[i].removeAttribute('selected')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.dom.outerHTML;
|
||||
},
|
||||
|
||||
writeIframe: function (content) {
|
||||
var w, doc, iframe = document.createElement('iframe'),
|
||||
f = document.body.appendChild(iframe);
|
||||
iframe.id = "myIframe";
|
||||
iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
|
||||
|
||||
w = f.contentWindow || f.contentDocument;
|
||||
doc = f.contentDocument || f.contentWindow.document;
|
||||
doc.open();
|
||||
doc.write(content);
|
||||
doc.close();
|
||||
this.toPrint(w, function () {
|
||||
document.body.removeChild(iframe)
|
||||
});
|
||||
},
|
||||
|
||||
toPrint: function (w, cb) {
|
||||
var _this = this;
|
||||
w.onload = function () {
|
||||
try {
|
||||
setTimeout(function () {
|
||||
w.focus();
|
||||
typeof _this.options.onStart === 'function' && _this.options.onStart();
|
||||
if (!w.document.execCommand('print', false, null)) {
|
||||
w.print();
|
||||
}
|
||||
typeof _this.options.onEnd === 'function' && _this.options.onEnd();
|
||||
w.close();
|
||||
cb && cb()
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
window.Print = Print;
|
||||
}(window, document));
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
export default {
|
||||
imgs: [
|
||||
'爱你',
|
||||
'爱情',
|
||||
'爱心',
|
||||
'傲慢',
|
||||
'白眼',
|
||||
'抱拳',
|
||||
'鄙视',
|
||||
'闭嘴',
|
||||
'便便',
|
||||
'擦汗',
|
||||
'菜刀',
|
||||
'差劲',
|
||||
'呲牙',
|
||||
'大哭',
|
||||
'蛋糕',
|
||||
'刀',
|
||||
'得意',
|
||||
'凋谢',
|
||||
'发呆',
|
||||
'NO',
|
||||
'OK',
|
||||
'发抖',
|
||||
'发怒',
|
||||
'饭',
|
||||
'飞吻',
|
||||
'奋斗',
|
||||
'疯了',
|
||||
'尴尬',
|
||||
'勾引',
|
||||
'鼓掌',
|
||||
'哈欠',
|
||||
],
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
新疆: [87.9236, 43.5883],
|
||||
|
||||
河南: [113.4668, 34.6234],
|
||||
西藏: [116.3896, 39.91],
|
||||
西藏: [91.091762, 30.037072],
|
||||
浙江: [119.5313, 29.8773],
|
||||
福建: [119.4543, 25.9222],
|
||||
湖南: [113.0823, 28.2568],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
/* @Print.js
|
||||
* DH (http://denghao.me)
|
||||
* 2017-7-14
|
||||
*/
|
||||
(function (window, document) {
|
||||
var Print = function (dom, options) {
|
||||
if (!(this instanceof Print)) return new Print(dom, options);
|
||||
|
||||
this.options = this.extend({
|
||||
noPrint: '.no-print',
|
||||
onStart: function () { },
|
||||
onEnd: function () { }
|
||||
}, options);
|
||||
|
||||
if ((typeof dom) === "string") {
|
||||
this.dom = document.querySelector(dom);
|
||||
} else {
|
||||
this.dom = dom;
|
||||
}
|
||||
|
||||
this.init();
|
||||
};
|
||||
Print.prototype = {
|
||||
init: function () {
|
||||
var content = this.getStyle() + this.getHtml();
|
||||
this.writeIframe(content);
|
||||
},
|
||||
extend: function (obj, obj2) {
|
||||
for (var k in obj2) {
|
||||
obj[k] = obj2[k];
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
getStyle: function () {
|
||||
var str = "",
|
||||
styles = document.querySelectorAll('style,link');
|
||||
for (var i = 0; i < styles.length; i++) {
|
||||
str += styles[i].outerHTML;
|
||||
}
|
||||
str += "<style>" + (this.options.noPrint ? this.options.noPrint : '.no-print') + "{display:none;}</style>";
|
||||
|
||||
return str;
|
||||
},
|
||||
|
||||
getHtml: function () {
|
||||
var inputs = document.querySelectorAll('input');
|
||||
var textareas = document.querySelectorAll('textarea');
|
||||
var selects = document.querySelectorAll('select');
|
||||
|
||||
for (var k in inputs) {
|
||||
if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
|
||||
if (inputs[k].checked == true) {
|
||||
inputs[k].setAttribute('checked', "checked")
|
||||
} else {
|
||||
inputs[k].removeAttribute('checked')
|
||||
}
|
||||
} else if (inputs[k].type == "text") {
|
||||
inputs[k].setAttribute('value', inputs[k].value)
|
||||
}
|
||||
}
|
||||
|
||||
for (var k2 in textareas) {
|
||||
if (textareas[k2].type == 'textarea') {
|
||||
textareas[k2].innerHTML = textareas[k2].value
|
||||
}
|
||||
}
|
||||
|
||||
for (var k3 in selects) {
|
||||
if (selects[k3].type == 'select-one') {
|
||||
var child = selects[k3].children;
|
||||
for (var i in child) {
|
||||
if (child[i].tagName == 'OPTION') {
|
||||
if (child[i].selected == true) {
|
||||
child[i].setAttribute('selected', "selected")
|
||||
} else {
|
||||
child[i].removeAttribute('selected')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.dom.outerHTML;
|
||||
},
|
||||
|
||||
writeIframe: function (content) {
|
||||
var w, doc, iframe = document.createElement('iframe'),
|
||||
f = document.body.appendChild(iframe);
|
||||
iframe.id = "myIframe";
|
||||
iframe.style = "position:absolute;width:0;height:0;top:-10px;left:-10px;";
|
||||
|
||||
w = f.contentWindow || f.contentDocument;
|
||||
doc = f.contentDocument || f.contentWindow.document;
|
||||
doc.open();
|
||||
doc.write(content);
|
||||
doc.close();
|
||||
this.toPrint(w, function () {
|
||||
document.body.removeChild(iframe)
|
||||
});
|
||||
},
|
||||
|
||||
toPrint: function (w, cb) {
|
||||
var _this = this;
|
||||
w.onload = function () {
|
||||
try {
|
||||
setTimeout(function () {
|
||||
w.focus();
|
||||
typeof _this.options.onStart === 'function' && _this.options.onStart();
|
||||
if (!w.document.execCommand('print', false, null)) {
|
||||
w.print();
|
||||
}
|
||||
typeof _this.options.onEnd === 'function' && _this.options.onEnd();
|
||||
w.close();
|
||||
cb && cb()
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
window.Print = Print;
|
||||
}(window, document));
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
</el-form>
|
||||
<el-descriptions title="配置项 " :column="1" border class="descriptions">
|
||||
<el-descriptions-item label="value"> 双向绑定的 value 值,使用示例:v-model='content' </el-descriptions-item>
|
||||
<el-descriptions-item label="参考文档"> <a href="https://www.wangeditor.com/v5/for-frame.html"> https://www.wangeditor.com/v5/for-frame.html </a> </el-descriptions-item>
|
||||
<el-descriptions-item label="参考文档"> <a href="https://www.wangeditor.com/v5/for-frame.html" target="_blank"> https://www.wangeditor.com/v5/for-frame.html </a> </el-descriptions-item>
|
||||
|
||||
</el-descriptions>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,42 @@
|
|||
<template>
|
||||
<u-container-layout>
|
||||
<div>
|
||||
<el-button type="primary" @click="print(1)">打印图片</el-button>
|
||||
<el-button type="primary" @click="print(2)">打印表格</el-button>
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<img :src="im1" style="width: 50%" />
|
||||
</div>
|
||||
<div>
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="date" label="日期" width="180" />
|
||||
<el-table-column prop="name" label="名字" width="180" />
|
||||
<el-table-column prop="address" label="地址" />
|
||||
</el-table>
|
||||
<div id="wrap" style="margin-bottom: 20px">
|
||||
<div>
|
||||
<el-button type="primary" @click="print(1)" >打印图片</el-button>
|
||||
<el-button type="primary" @click="print(2)">打印Json数据</el-button>
|
||||
<el-button type="primary" @click="print(3)">打印HTML</el-button>
|
||||
</div>
|
||||
<div style="margin-top: 20px">
|
||||
<img :src="printImg" style="width: 300px" />
|
||||
</div>
|
||||
<div id="tableBox">
|
||||
<el-table :data="tableData" style="width: 100%">
|
||||
<el-table-column prop="date" label="日期" width="180" />
|
||||
<el-table-column prop="name" label="名字" width="180" />
|
||||
<el-table-column prop="address" label="地址" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-descriptions title="配置项 " :column="1" border class="descriptions">
|
||||
<el-descriptions-item label="官方文档"> <a href="https://github.com/crabbly/Print.js" target="_blank">https://github.com/crabbly/Print.js</a> </el-descriptions-item>
|
||||
<el-descriptions-item label="printable"> 文档来源:pdf或图像的url,html元素的id或json数据的对象 </el-descriptions-item>
|
||||
<el-descriptions-item label="type"> 可打印类型。可用的打印选项包括:pdf,html,image,json和raw-html。 </el-descriptions-item>
|
||||
<el-descriptions-item label="documentTitle"> 打印html,image或json时,它将显示为文档标题。如果用户尝试将打印作业保存为pdf文件,它也将是文档的名称。 </el-descriptions-item>
|
||||
<el-descriptions-item label="scanStyles">设置为false时,库不会处理应用于正在打印的html的样式。使用css参数时很有用 </el-descriptions-item>
|
||||
<el-descriptions-item label="targetStyle"> 默认情况下,在打印HTML元素时,库仅处理某些样式。此选项允许您传递要处理的样式数组。例如:['padding-top','border-bottom'] </el-descriptions-item>
|
||||
<el-descriptions-item label="gridHeaderStyle"> 打印JSON数据时网格标题的可选样式。 </el-descriptions-item>
|
||||
<el-descriptions-item label="properties"> 在打印JSON时使用。这些是对象属性名称。 </el-descriptions-item>
|
||||
<el-descriptions-item label="honorColor"> 要以彩色打印文本,请将此属性设置为true。默认情况下,所有文本都将以黑色打印。 </el-descriptions-item>
|
||||
<el-descriptions-item label="css"> 这允许我们传递一个或多个应该应用于正在打印的html的css文件URL。值可以是包含单个URL的字符串,也可以是包含多个URL的数组。 </el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</u-container-layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import printJS from 'print-js'
|
||||
import im1 from '@/assets/image/im1.jpeg'
|
||||
import '@/utils/Print'
|
||||
import printImg from '@/assets/image/im1.jpeg'
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
|
|
@ -49,7 +66,7 @@
|
|||
case 1:
|
||||
printJS({
|
||||
type: 'image',
|
||||
printable: im1,
|
||||
printable: [printImg],
|
||||
documentTitle: '打印图片',
|
||||
})
|
||||
break
|
||||
|
|
@ -67,6 +84,24 @@
|
|||
})
|
||||
break
|
||||
case 3:
|
||||
// printJS({
|
||||
// type: 'wrap',
|
||||
// documentTitle: '打印页面',
|
||||
// printable: "tableBox",
|
||||
// scanStyles:false,
|
||||
// targetStyles: ['*'], // 允许打印所有样式属性
|
||||
// honorColor: true, // 是否打印彩色文本
|
||||
// style: '@page {margin: 0 10mm};', // 不打印页眉和页脚
|
||||
// gridStyle: 'border: 1px solid lightgray;font-size: 12px;',
|
||||
// })
|
||||
Print('#wrap', {
|
||||
onStart: function () {
|
||||
console.log('onStart', new Date())
|
||||
},
|
||||
onEnd: function () {
|
||||
console.log('onEnd', new Date())
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,31 +2,66 @@
|
|||
<u-container-layout>
|
||||
<el-input v-model="inputData" placeholder="请输入" style="width: 400px; max-width: 100%" />
|
||||
<el-button type="primary" @click="handleQrcode(1)">
|
||||
<el-icon style="margin-right: 6px"><collection /></el-icon> 生成二维码
|
||||
<el-icon style="margin-right: 6px"><collection /></el-icon> 生成普通二维码
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleQrcode(2)">生成带logo</el-button>
|
||||
<el-button type="primary" @click="handleQrcode(3)">生成随机颜色二维码</el-button>
|
||||
<el-button type="primary" @click="handleQrcode(4)">下载</el-button>
|
||||
<div>
|
||||
<vue-qr :logoSrc="src" :text="inputData" :size="200"></vue-qr>
|
||||
<vue-qr :logoSrc="logoSrc" :text="inputData" :size="200" :callback="qrcodeCallback" :color-dark="randomColor" ></vue-qr>
|
||||
</div>
|
||||
|
||||
<el-descriptions title="配置项 " :column="1" border class="descriptions">
|
||||
<el-descriptions-item label="官方文档"> <a href="https://github.com/Binaryify/vue-qr" target="_blank">https://github.com/Binaryify/vue-qr</a> </el-descriptions-item>
|
||||
<el-descriptions-item label="text"> 二维码内容,默认为 'https://github.com/zouzhibin/vue-admin-perfect' </el-descriptions-item>
|
||||
<el-descriptions-item label="logoSrc"> 嵌入至二维码中心的 LOGO 地址 </el-descriptions-item>
|
||||
<el-descriptions-item label="size"> 尺寸, 长宽一致, 包含外边距,默认为 200 </el-descriptions-item>
|
||||
<el-descriptions-item label="margin"> 二维码图像的外边距, 默认 20px </el-descriptions-item>
|
||||
<el-descriptions-item label="logoMargin"> 标识周围的空白边框, 默认为0 </el-descriptions-item>
|
||||
<el-descriptions-item label="correctLevel"> 容错级别 0-3 </el-descriptions-item>
|
||||
<el-descriptions-item label="autoColor"> 若为 true, 背景图的主要颜色将作为实点的颜色, 即 colorDark,默认 true </el-descriptions-item>
|
||||
<el-descriptions-item label="colorDark"> 实点的颜色,默认颜色值 =>黑色 </el-descriptions-item>
|
||||
<el-descriptions-item label="colorLight"> 空白区的颜色 </el-descriptions-item>
|
||||
<el-descriptions-item label="callback"> 生成的二维码 Data URI 可以在回调中取得,第一个参数为二维码 data URL, 第二个参数为 props 传过来的 qid(因为二维码生成是异步的,所以加个 id 用于排序) </el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</u-container-layout>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
import vueQr from 'vue-qr/src/packages/vue-qr.vue'
|
||||
import three from '@/assets/logo.png'
|
||||
const src = ref(null)
|
||||
const src2 = ref()
|
||||
import clip from '@/utils/clipboard'
|
||||
import { getColor } from '@/utils/index'
|
||||
const logoSrc = ref(null)
|
||||
const qrcodeUrl = ref(null)
|
||||
const randomColor = ref('black')
|
||||
const inputData = ref('https://github.com/zouzhibin/vue-admin-perfect')
|
||||
|
||||
const handleQrcode = (type) => {
|
||||
switch (type) {
|
||||
case 1:
|
||||
src.value = null
|
||||
randomColor.value = 'black'
|
||||
logoSrc.value = null
|
||||
return
|
||||
case 2:
|
||||
src.value = three
|
||||
logoSrc.value = three
|
||||
return
|
||||
case 3:
|
||||
randomColor.value = getColor()
|
||||
return
|
||||
case 4:
|
||||
let name = new Date().getTime();
|
||||
let a = document.createElement("a");
|
||||
a.style.display = "none";
|
||||
a.download = name;
|
||||
a.href = qrcodeUrl.value;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove()
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const qrcodeCallback = (url)=>{
|
||||
qrcodeUrl.value = url
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
51
yarn.lock
51
yarn.lock
|
|
@ -734,11 +734,24 @@ async@^3.2.3:
|
|||
resolved "https://registry.npmmirror.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
|
||||
integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
atob@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||
|
||||
axios@^0.27.2:
|
||||
version "0.27.2"
|
||||
resolved "https://registry.npmmirror.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
|
||||
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
|
||||
dependencies:
|
||||
follow-redirects "^1.14.9"
|
||||
form-data "^4.0.0"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
|
|
@ -988,6 +1001,13 @@ color-name@~1.1.4:
|
|||
resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@^2.20.3:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
|
|
@ -1202,6 +1222,11 @@ define-property@^2.0.2:
|
|||
is-descriptor "^1.0.2"
|
||||
isobject "^3.0.1"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
delegate@^3.1.2:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.npmmirror.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
|
||||
|
|
@ -1851,11 +1876,25 @@ flatted@^3.1.0:
|
|||
resolved "https://registry.npmmirror.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2"
|
||||
integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==
|
||||
|
||||
follow-redirects@^1.14.9:
|
||||
version "1.15.1"
|
||||
resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
|
||||
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
|
||||
|
||||
for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmmirror.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
frac@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b"
|
||||
|
|
@ -2629,6 +2668,11 @@ micromatch@^4.0.4:
|
|||
braces "^3.0.2"
|
||||
picomatch "^2.3.1"
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-match@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz#3f87c31e9af1a5fd485fb9db134428b23bbb7ba8"
|
||||
|
|
@ -2636,6 +2680,13 @@ mime-match@^1.0.2:
|
|||
dependencies:
|
||||
wildcard "^1.1.0"
|
||||
|
||||
mime-types@^2.1.12:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mimic-response@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
|
||||
|
|
|
|||
Loading…
Reference in New Issue