Commit 07be8f87 by renjihua

Initial commit

parents
.DS_Store
config/cc/
node_modules/
dist/
dist.zip
prodTestDist/
prodTestDist.zip
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json
companyDist/
companyDist.zip
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>晶科MES</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/lib/main.js"></script>
</body>
</html>
import resize from "@/components/Charts/mixins/resize";
import {FitTable} from "@/components/FitTable";
import Hamburger from "@/components/Hamburger/index.vue";
import Pagination from "@/components/Pagination/index.vue";
import IndexPageSize from "@/components/Pagination/indexPageSize.vue";
import ScrollPane from "@/components/ScrollPane/index.vue";
import SelectTree from "@/components/selectTree/index.vue";
import StatusText from "@/components/StatusText/index.vue";
import SvgIcon from "@/components/SvgIcon/index.vue";
import Switcher from "@/components/Switcher/index.vue";
export {
resize,
FitTable,
Hamburger,
Pagination,
IndexPageSize,
ScrollPane,
SelectTree,
StatusText,
SvgIcon,
Switcher,
}
{
"name": "mes-template",
"version": "3.8.0",
"license": "MIT",
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint",
"author": "Pan <panfree23@gmail.com>",
"scripts": {
"dev": "vite",
"build": "vite build",
"build:prodTest": "vite build --mode prodTest --outDir prodTestDist",
"build:companyTest": "vite build --mode companyEnv --outDir companyDist",
"preview": "vite preview"
},
"dependencies": {
"@riophae/vue-treeselect": "^0.4.0",
"axios": "0.18.0",
"clipboard": "^2.0.4",
"echarts": "^5.0.0",
"element-ui": "2.15.6",
"fast-glob": "^3.2.11",
"jquery": "^3.4.1",
"js-cookie": "2.2.0",
"jsbarcode": "^3.11.0",
"lodash-es": "^4.17.21",
"moment": "^2.22.2",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-browserify": "^1.0.1",
"qrcodejs2": "0.0.2",
"qrcodejs2-fix": "^0.0.1",
"sortablejs": "1.14.0",
"umy-ui": "^1.1.6",
"v-scale-screen": "^1.0.0",
"vue": "2.6.14",
"vue-clipboards": "^1.3.0",
"vue-codemirror": "^4.0.6",
"vue-color": "^2.7.0",
"vue-router": "^3.0.7",
"vue-seamless-scroll": "^1.1.23",
"vue-template-compiler": "2.6.14",
"vue2-ace-editor": "^0.0.15",
"vuedraggable": "^2.23.0",
"vuex": "^3.0.1",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@riophae/vue-treeselect": "^0.4.0",
"@rollup/plugin-commonjs": "^21.0.3",
"fast-glob": "^3.2.11",
"less": "^3.0.0",
"less-loader": "^4.1.0",
"querystring": "^0.2.1",
"rollup-plugin-copy": "^3.4.0",
"sass": "^1.50.0",
"vite": "^2.9.13",
"vite-plugin-svg-icons": "^2.0.1",
"vite-plugin-vue2": "^1.4.4"
}
}
import { debounce } from '@/utils'
export default {
data() {
return {
$_sidebarElm: null
}
},
mounted() {
this.__resizeHandler = debounce(() => {
if (this.chart) {
console.log('resize')
this.chart.resize()
}
}, 100)
window.addEventListener('resize', this.__resizeHandler)
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
activated() {
if (this.chart) {
console.log('activated, resize')
this.__resizeHandler()
}
},
beforeDestroy() {
window.removeEventListener('resize', this.__resizeHandler)
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
},
methods: {
// use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.__resizeHandler()
}
}
}
}
import FitTable from './table'
import FitTableColumn from './table-column'
FitTable.install = (Vue, {
table = 'ElTable',
column = 'ElTableColumn'
} = {}) => {
Vue.component(table || FitTable.name, FitTable)
Vue.component(column || FitTableColumn.name, FitTableColumn)
}
export {
FitTable,
FitTableColumn
}
export default FitTable
import { TableColumn } from 'element-ui'
export default {
name: 'ElTableColumn',
extends: TableColumn,
props: {
maxWidth: {
type: Number
}
},
data() {
return {
timer: null
}
},
beforeDestroy() {
clearTimeout(this.timer)
this.timer = null
},
mounted() {
// 设置默认的table-column 表头渲染,判断当出现省略号时el.offsetWidth < el.scrollWidth, 悬浮显示toolTip,
// 采用jsx 语法进行书写, 加延迟目的: 渲染完毕还未获取到是否超出内容的条件
this.timer = setTimeout(() => {
if (this.columnConfig.type === 'selection') {
return
}
this.columnConfig.renderHeader = (h, { column }) => {
const { label, id } = column
const el = document.querySelector(`.${id} .cell`)
const eleWidth = el && el.offsetWidth
if (el && (eleWidth < el.scrollWidth)) { // 表示超出了,有省略号出现
return (<el-tooltip class='item' effect='dark' content={label} placement='top'>
<span >{label}</span>
</el-tooltip>)
} else {
return <span>{ label }</span>
}
}
}, 500)
}
}
import { Table } from 'element-ui'
import { getTextWith } from './utils'
export default {
name: 'ElTable',
extends: Table,
props: {
// Set auto-fit column's width
autoFitColumn: {
type: Boolean,
default: false
}
},
watch: {
data() {
// 每一行数据
this.$nextTick(() => this.setAutoFitColumn())
},
columns() {
// 每一列
this.$nextTick(() => this.setAutoFitColumn())
},
// 只适配某些字段列
fitColumns() {
this.$nextTick(() => this.setAutoFitColumn())
}
},
methods: {
// support max-width
initColsObj() {
this.colObjs = this.$children.reduce((prev, cur) => {
if (cur.prop) {
prev[cur.prop] = cur.maxWidth || cur.$attrs['max-width'] || 0
}
return prev
}, {})
},
/* 根据每一项field进行分组,形成field: [....],这样就拿到了每一页的,根据键名,键值为所有数据的宽度的最大值的集合*/
flattenData(data) {
if (!Array.isArray(data)) return {}
return data.reduce((acc, cur) => {
for (const item in cur) {
if (!acc[item]) acc[item] = []
acc[item].push(getTextWith(cur[item]))
acc[item] = [Math.max(...acc[item])]
}
return acc
}, {})
},
setAutoFitColumn() {
// It's false, Use original el-table
if (!this.autoFitColumn) return
if (!this.data) return
const collectionData = this.flattenData(this.data)
// console.log('cc---',collectionData)
this.initColsObj()
this.handlerAutoFitColumn(collectionData)
},
handlerAutoFitColumn(data) {
const columns = this.layout.getFlattenColumns()
// Each column's settings
this.columns.forEach((col, idx) => {
const curColumn = columns.find(item => item.id === col.id)
// It's not exist in fit-columns array
if (this.fitColumns && this.fitColumns.length && !this.fitColumns.includes(curColumn.property)) return
// 获取设定的最大宽度
const maxWidth = this.colObjs[curColumn.property] || 0
// th header Width
const thColWidth = getTextWith(col.label) + 30
// console.log(122,col.label)
// td width
const tdColWidth = data[curColumn.property] ? data[curColumn.property][0] + 50 : 0
// adjust minimum width of every columns
let minWidth = Math.ceil(
Math.max(
col.sortable ? thColWidth + 17 : thColWidth,
tdColWidth,
)
)
// console.log('min',minWidth)
// 宽度超过200,表示字数超过20个,显示提示
if (minWidth > 200) { minWidth = 230 }
curColumn.minWidth = maxWidth ? Math.min(maxWidth, minWidth) : minWidth + 20
})
// run once layout api
this.doLayout()
this.$emit('doLayout')
}
}
}
// 计算字体的宽度大小
export function getTextWith(text) {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
return Math.ceil(context.measureText(text).width)
}
<template>
<div>
<svg
:class="{'is-active':isActive}"
t="1492500959545"
class="hamburger"
style="fill: #fff"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1691"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="64"
height="64"
@click="toggleClick">
<path
d="M966.8023 568.849776 57.196677 568.849776c-31.397081 0-56.850799-25.452695-56.850799-56.850799l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 543.397081 998.200404 568.849776 966.8023 568.849776z"
p-id="1692" />
<path
d="M966.8023 881.527125 57.196677 881.527125c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.849776 56.850799-56.849776l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.849776l0 0C1023.653099 856.07443 998.200404 881.527125 966.8023 881.527125z"
p-id="1693" />
<path
d="M966.8023 256.17345 57.196677 256.17345c-31.397081 0-56.850799-25.452695-56.850799-56.849776l0 0c0-31.397081 25.452695-56.850799 56.850799-56.850799l909.605623 0c31.397081 0 56.849776 25.452695 56.849776 56.850799l0 0C1023.653099 230.720755 998.200404 256.17345 966.8023 256.17345z"
p-id="1694" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
},
toggleClick: {
type: Function,
default: null
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
cursor: pointer;
width: 20px;
height: 20px;
transform: rotate(90deg);
transition: .38s;
transform-origin: 50% 50%;
}
.hamburger.is-active {
transform: rotate(0deg);
}
</style>
<template>
<div>
<el-pagination
:current-page="pageData.page"
:page-sizes="[5,10, 20, 30, 40]"
:page-size="pageData.size"
:total="pageData.total"
class="admin_pagination"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"/>
</div>
</template>
<script>
export default {
components: {
},
props: {
pageData: {
type: Object,
default: () => {
return {}
}
},
changePageData: {
type:Function,
default: () => {}
}
},
data() {
return {
}
},
methods: {
handleSizeChange(val) {
if(this.$parent.changePageData) {
this.$parent.changePageData('size', val)
} else {
this.changePageData('size', val)
}
},
handleCurrentChange(val) {
if(this.$parent.changePageData) {
this.$parent.changePageData('page', val)
} else {
this.changePageData('page', val)
}
}
}
}
</script>
<template>
<div class="pageContain">
<el-pagination
style="padding:10px;float:right"
:current-page="pageData.page"
:page-sizes="pageSize"
:page-size="pageData.size"
:total="pageData.total"
class="admin_pagination"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"/>
</div>
</template>
<script>
export default {
components: {
},
props: {
pageData: {
type: Object,
default: () => {
return {}
}
},
changePageData: {
type: Function,
required: true
},
pageSize: {
type: Array,
default: () => [5,10, 20, 30, 40]
}
},
data() {
return {
}
},
computed: {
},
watch: {
},
created() {
},
mounted() {
},
methods: {
handleSizeChange(val) {
this.changePageData('size', val)
},
handleCurrentChange(val) {
this.changePageData('page', val)
}
}
}
</script>
<style scoped lang="scss">
.pageContain{
// background: red;
display: flex;
justify-content: flex-start;
}
</style>
<template>
<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
<slot/>
</el-scrollbar>
</template>
<script>
const padding = 15 // tag's padding
export default {
name: 'ScrollPane',
data() {
return {
left: 0
}
},
methods: {
handleScroll(e) {
const eventDelta = e.wheelDelta || -e.deltaY * 40
const $scrollWrapper = this.$refs.scrollContainer.$refs.wrap
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
},
moveToTarget($target) {
const $container = this.$refs.scrollContainer.$el
const $containerWidth = $container.offsetWidth
const $scrollWrapper = this.$refs.scrollContainer.$refs.wrap
const $targetLeft = $target.offsetLeft
const $targetWidth = $target.offsetWidth
if ($targetLeft > $containerWidth) {
// tag in the right
$scrollWrapper.scrollLeft = $targetLeft - $containerWidth + $targetWidth + padding
} else {
// tag in the left
$scrollWrapper.scrollLeft = $targetLeft - padding
}
}
}
}
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.scroll-container {
white-space: nowrap;
position: relative;
overflow: hidden;
width: 100%;
::v-deep {
.el-scrollbar__bar {
bottom: 0px;
.el-scrollbar__wrap {
height: 49px;
}
}
}
}
</style>
<template>
<div>
<span :class="renderClass" :style="ownStyle"/>
<span>{{ text }}</span>
</div>
</template>
<script>
export default {
props: {
text: {
type: String,
default: ''
},
type: {
type: String,
default: 'default'
},
// 可以单独设置样式 background等
ownStyle: {
type: Object,
default: () => { return {} }
}
},
data() {
return {
map: {
'success': 'success-circle',
'warning': 'warning-circle',
'info': 'info-circle',
'danger': 'danger-circle',
'default': 'default-circle'
}
}
},
computed: {
renderClass() {
if (this.type) {
return { [this.map[this.type]]: true, 'circle': true }
} else {
return { circle: true }
}
}
}
}
</script>
<style scoped>
.circle {
width: 6px;
height: 6px;
border-radius: 50%;
display: inline-block;
margin-right: 6px;
}
.success-circle {
background: #67C239;
}
.warning-circle {
background: #E6A13B;
}
.info-circle {
background: #e9e9eb;
}
.danger-circle {
background: #F56C6C;
}
.default-circle {
background: #409eff;
}
</style>
<template>
<svg :class="svgClass" aria-hidden="true">
<use :xlink:href="iconName"/>
</svg>
</template>
<script>
export default {
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
computed: {
iconName() {
return `#icon-svg-${this.iconClass}`
},
svgClass() {
if (this.className) {
return 'svg-icon ' + this.className
} else {
return 'svg-icon'
}
}
}
}
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
<!-- 开关的按钮组件 -->
<template>
<div class="m-switch-wrap">
<div @click="disabled ? e => e.preventDefault() : onSwitch()"
:class="['m-switch', { 'switch-checked': checked, 'disabled': disabled }]">
<div :class="['u-switch-inner', checked ? 'inner-checked' : 'inner-unchecked']">
{{ checked ? checkedInfo : uncheckedInfo }}</div>
<div :class="['u-node', { 'node-checked': checked }]"></div>
</div>
</div>
</template>
<script>
export default {
name: 'Switcher',
props: {
defaultChecked: { // 初始是否选中
type: Boolean,
default: false
},
checkedInfo: { // 选中时的内容
type: [Number, String],
default: null
},
uncheckedInfo: { // 未选中时的内容
type: [Number, String],
default: null
},
disabled: { // 是否禁用
type: Boolean,
default: false
}
},
data() {
return {
checked: this.defaultChecked
}
},
methods: {
onSwitch() {
// console.log('checked:', this.checked)
if (this.checked == true) {
this.$confirm('确定要取消必检?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$message({ type: 'success', message: '取消成功' })
this.checked = !this.checked
// console.log(this.checked,"this.checked.321");
})
} else if (this.checked == false) {
this.$confirm('确定要开启必检吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$message({ type: 'success', message: '开启成功' })
this.checked = !this.checked
// console.log(this.checked, "this.checked.654");p
})
}
}
}
}
</script>
<style lang="scss" scoped>
.m-switch-wrap {
height: 22px;
min-width: 44px;
display: inline-block;
.m-switch {
position: relative;
height: 22px;
color: rgba(0, 0, 0, .65);
font-size: 14px;
background: rgba(0, 0, 0, .25);
border-radius: 100px;
cursor: pointer;
transition: background .36s;
.u-switch-inner {
// display: inline-block;
color: #fff;
font-size: 14px;
line-height: 22px;
padding: 0 8px;
transition: all .36s;
}
.inner-checked {
margin-right: 18px;
}
.inner-unchecked {
margin-left: 18px;
}
.u-node {
position: absolute;
top: 3px;
left: 2px;
width: 18px;
height: 18px;
background: #FFF;
border-radius: 100%;
cursor: pointer;
transition: all .36s;
}
.node-checked {
// 结果等价于right: 2px; 为了滑动效果都以左边为基准进行偏移
left: 100%;
margin-left: -2px;
transform: translateX(-100%);
}
}
.switch-checked {
background:#1890FF;
margin-top: 11px;
}
.disabled {
cursor: not-allowed;
opacity: .4;
}
}
</style>
\ No newline at end of file
<!--通用选择树-->
<template>
<div class="aside" :class="readOnly ? 'aside-label' : ''">
<div class="aside-title" v-if="title || !readOnly">
<strong>{{ title }}</strong>
<el-button type="text" v-if="!readOnly" style="float: right;" icon="el-icon-plus" @click="create('',0)">新增</el-button>
</div>
<div :class="(typeList.length > 0 || defaultProps.otherType || defaultProps.type) ? 'tree-left' : ''">
<treeselect
v-model="id"
:options="treeTableList"
:normalizer="normalizer"
:default-expand-level="2"
:max-height="480"
alwaysOpen
show-count
:multiple="multiple"
sort-value-by="INDEX"
value-consists-of="ALL_WITH_INDETERMINATE"
placeholder="搜索"
no-results-text="暂无数据"
no-options-text="暂无数据"
@input="handleInput"
@select="select">
<template v-slot:option-label="{ node, shouldShowCount, count, labelClassName, countClassName }">
<label :class="labelClassName" class="tree-label" @click="handleSelect(node)">
{{ node.label }}
<!--count-->
<span v-if="shouldShowCount" :class="countClassName">({{ count }})</span>
</label>
<template v-if="!readOnly">
<!--btn-->
<span class="tree-btn">
<el-button
type="text"
size="mini"
icon="el-icon-edit"
@click="update(node)">
</el-button>
<el-dropdown @command="create(node,$event)" >
<span class="el-dropdown-link">
<i class="el-icon-plus" style="color: #409EFF"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :command="1">创建同级节点</el-dropdown-item>
<el-dropdown-item :command="2" :disabled='createDisabled(node.raw)'>创建子级节点</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button
class="table-delBtn"
type="text"
size="mini"
icon="el-icon-delete"
@click="remove(node.raw.id)">
</el-button>
</span>
</template>
<el-tag class="tree-tag" v-if="getType(node.raw)">{{ getType(node.raw) }}</el-tag>
</template>
</treeselect>
</div>
</div>
</template>
<script>
import { cloneDeep } from 'lodash-es'
const defaultProps = {
label:'label',//节点名称
type:'type',//节点类型名称
code:'code',//节点编码
otherType:'',//其他节点类型名称
}
export default {
name: 'SelectTree',
props: {
//选择项
selectId:{
type:[String,Number,Array],
default:0
},
// 是否只读
// true: 不能新增编辑
// false: 可以新增编辑
readOnly: {
type: Boolean,
default: true
},
//是否多选
multiple: {
type: Boolean,
default: false
},
//树结构数据源
treeTableList:{
type: Array,
require:true
},
typeList:{
type: Array,
default:()=>[]
},
//预设数据结构统一数据类型,对照传入的数据,默认数据结构查看defaultProps
props:{
type: Object,
default:()=>{}
},
//标题
title:{
type: String,
default: ''
},
typeWidth:{
type: Number,
default:35
},
createDisabled:{
type: Function,
default:()=>{return false}
}
},
computed:{
id: {
get() {
if(this.multiple){
return Array.isArray(this.selectId) ? this.selectId : []
}else{
return this.selectId || null
}
},
set(selectId) {
this.$emit('update:selectId', selectId)
}
}
},
data() {
return {
selectNode:{},
defaultProps:{}
}
},
mounted(){
this.defaultProps = cloneDeep(defaultProps)
for(let key in this.props){
this.defaultProps[key] = this.props[key]
}
},
methods: {
getType(raw){
if(this.typeList.length > 0){
const data = this.typeList.find(item => item.value === raw[this.defaultProps.type])
return data ? data.label : raw[this.defaultProps.otherType] || ''
}else{
return raw[this.defaultProps.type]
}
},
//创建
create(node,type) {
this.$emit('tree-create', node, type)
},
//修改
update(node) {
this.$emit('tree-update', node)
},
//删除
remove(id){
this.$confirm('是否确定要删除?删除后无法恢复', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$emit('tree-remove', id)
}).catch(() => {})
},
normalizer(node){
// 去掉children=[]的children属性
if (node.children && !node.children.length) {
delete node.children
}
return {
id: node.id,
label: node[this.defaultProps.code] + '-' + node[this.defaultProps.label],
children: node.children
}
},
handleInput(value) {
if (!value) {
this.selectNode = {}
this.$emit('node-click', this.selectNode)
}
},
select(value){
},
//获取所有子集id集合
getCheckedKeys(){
if(this.multiple){
return this.id
}
const ids = []
if(this.selectId && JSON.stringify(this.selectNode) === '{}'){
this.getCurrentData(this.treeTableList)
}
if(JSON.stringify(this.selectNode) !== '{}'){
this.recursion([this.selectNode],ids)
}
return ids
},
//用于回显后未点击获取当前选中数据
getCurrentData(list){
list.forEach(element => {
if(element.id === Number(this.selectId)){
this.selectNode = cloneDeep(element)
return
}
if(element.children && element.children.length > 0)this.getCurrentData(element.children)
});
},
//获取所current有子集id
recursion(list,ids){
list.forEach(element => {
ids.push(element.id)
if(element.children && element.children.length > 0)this.recursion(element.children,ids)
});
},
//选择和点击事件,具体要返回那些信息可以自行在后面node-click的参数增加
handleSelect(node) {
this.selectNode = node.raw
this.$emit('node-click', node )
},
}
}
</script>
<style lang="scss" scoped>
.aside{
.tree-left{
::v-deep .vue-treeselect__indent-level-0{
padding-left:45px
}
::v-deep .vue-treeselect__label-container{
display: flex;
justify-content: space-between;
}
::v-deep .vue-treeselect__label{
width: calc(100% - 50px);
}
.tree-tag{
position: absolute;
left: 5px;
height: 20px;
padding: 0 5px;
line-height: 20px;
text-align: center;
width: 35px;
overflow: hidden;
}
}
}
.aside-label{
width: 100%;
height: 100%;
::v-deep .vue-treeselect__label{
width: 100%;
}
}
</style>
// import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
return window.sessionStorage.getItem(TokenKey)
}
export function setToken(token) {
return window.sessionStorage.setItem(TokenKey, token)
}
export function removeToken() {
return window.sessionStorage.removeItem(TokenKey)
}
import axios from 'axios'
import { getToken } from './auth'
import { Message, MessageBox } from 'element-ui'
import { showLoading, closeLoading } from '@/utils/showOrHideLoading'
axios.defaults.headers.common['token'] = getToken()
/**
* @author renwenji
* @date 2020/1/9
* @Description: 导出excel的方法
* @params1: url 请求的地址
* @params2: data 传递的数据参数
* @returns: promise 成功resolve 失败reject
*/
export function exportExcel(url,data={}) {
return new Promise((resolve, reject) => {
showLoading()
axios({
url,
method: 'GET',
params:data,
responseType: 'blob' // 非常重要
}).then(response => {
closeLoading()
console.log('response', response)
const { data } = response
const reader = new FileReader()
reader.readAsText(data)
resolve(response)
})
.catch(error => {
closeLoading()
Message({
message: '数据为空或其他错误,无法导出!',
type: 'error',
duration: 5 * 1000
})
reject(error)
})
})
}
// 创建对象url
function createObjectURL(blob) {
if (window.URL) {
return window.URL.createObjectURL(blob)
} else if (window.webkitURL) {
return window.webkitURL.createObjectURL(blob)
} else {
return null
}
}
// 释放对象url资源
function revokeObjectURL(url) {
if (window.URL) {
window.URL.revokeObjectURL(url)
} else if (window.webkitURL) {
window.webkitURL.revokeObjectURL(url)
}
}
/**
* @author renwenji
* @date 2020/1/9
* @Description: 下载excel,动态添加a标签、下载后移除
* @params1: response
* @params2: fileName 下载的文件名
*/
export function downLoadExcel(response, fileName) {
const url = createObjectURL(new Blob([response.data]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', fileName)
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
revokeObjectURL(url)
}
// 确认导出
export function confirmExportExcel(url, fileName) {
MessageBox.confirm('确定进行导出操作?', '确认信息', {
distinguishCancelAndClose: true,
confirmButtonText: '确定',
cancelButtonText: '取消'
})
.then(() => {
exportExcel(url).then(res => {
downLoadExcel(res, fileName)
Message({
message: '导出成功!',
type: 'success',
duration: 5 * 1000
})
})
}).catch(action => {
Message({
message: '已取消操作!',
type: 'info',
duration: 5 * 1000
})
})
}
/**
* formData的导出Excel
* @param url
* @param data
* @returns {Promise<unknown>}
*/
export function formDataExportExcel(url, data) {
return new Promise((resolve, reject) => {
axios({
url: url,
method: 'POST', //请求方式
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data,
responseType: 'blob' // 非常重要
}).then(response => {
const { data } = response
// 解析错误返回的信息
if (data.type.includes('application/json')) {
const reader = new FileReader()
reader.onload = function(event) {
const content = reader.result
const message = JSON.parse(content).message
Message({
message,
type: 'error',
duration: 5 * 1000
})
}
reader.readAsText(data)
return true
}
// excel格式
// const types = ['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
// if (types.includes(data.type)) {
resolve(response)
// }
}).catch(error => {
console.log('error ==', error)
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
reject(error)
})
})
}
/**
* Created by jiachenpan on 16/11/18.
*/
export function getDefaultData() {
const month = new Date().getMonth()
const date = new Date()
const end = new Date(`${month === 0 ? date.getFullYear() - 1 : date.getFullYear()}-${month === 0 ? '12' : month + 1}-&${date.getDate()} 09:00:00`)
const start = new Date()
start.setTime(end.getTime() - 3600 * 1000 * 24)
return [parseTime(start, '{y}-{m}-{d} {h}:{i}:{s}'), parseTime(end, '{y}-{m}-{d} {h}:{i}:{s}')]
}
export function parseTime(time, cFormat) {
if (arguments.length === 0) {
return null
}
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if (('' + time).length === 10) time = parseInt(time) * 1000
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
export function formatTime(time, option) {
time = +time * 1000
const d = new Date(time)
const now = Date.now()
const diff = (now - d) / 1000
if (diff < 30) {
return '刚刚'
} else if (diff < 3600) {
// less 1 hour
return Math.ceil(diff / 60) + '分钟前'
} else if (diff < 3600 * 24) {
return Math.ceil(diff / 3600) + '小时前'
} else if (diff < 3600 * 24 * 2) {
return '1天前'
}
if (option) {
return parseTime(time, option)
} else {
return (
d.getMonth() +
1 +
'月' +
d.getDate() +
'日' +
d.getHours() +
'时' +
d.getMinutes() +
'分'
)
}
}
/**
* @param {Function} func
* @param {number} wait
* @param {boolean} immediate
* @return {*}
*/
export function debounce(func, wait, immediate) {
let timeout, args, context, timestamp, result
const later = function() {
// 据上一次触发时间间隔
const last = +new Date() - timestamp
// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
}
return function(...args) {
context = this
timestamp = +new Date()
const callNow = immediate && !timeout
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait)
if (callNow) {
result = func.apply(context, args)
context = args = null
}
return result
}
}
/**
* 创建并返回一个像节流阀一样的函数,当重复调用函数的时候,最多每隔delay毫秒调用一次该函数
* @param func 执行函数
* @param delay 时间间隔
* @return {Function}
*/
export function throttle(func, delay) {
let timeStamp = new Date()
return function(...args) {
const context = this
if (new Date() - timeStamp > delay) {
timeStamp = new Date()
func.apply(context, args)
}
}
}
/**
* @date 2019/11/22
* @Description: 将中文转为unicode英文
* @params1: text {string} 转化前的中文
* @returns: 转化后的unicode
*/
export function transferEncodeText(text) {
if (text == null) {
return ''
}
var newText = ''
for (var i = 0; i < text.length; i++) {
var code = text.charCodeAt(i)
if (code >= 128 || code == 91 || code == 93) {
// 91 is "[", 93 is "]".
newText += '[' + code.toString(16) + ']'
} else {
newText += text.charAt(i)
}
}
return newText
}
/**
* 行列转换
* @param {array} arr
* @return {array} res
*/
export function transformRowColumn(arr) {
const res = []
const firstItem = arr[0]
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < firstItem.length; j++) {
if (!Array.isArray(res[j])) res[j] = []
res[j].push(arr[i][j])
}
}
return res
}
/**
* 解决帆软报表有汉字参数的乱码
* @param {string} text
* @return {string} newText
*/
export function cjkEncode(text) {
if (text == null) {
return ''
}
var newText = ''
for (var i = 0; i < text.length; i++) {
var code = text.charCodeAt(i)
if (code >= 128 || code === 91 || code === 93) { // 91 is "[", 93 is "]".
newText += '[' + code.toString(16) + ']'
} else {
newText += text.charAt(i)
}
}
return newText
}
export function initDate(subDay) {
var time = []
var date = new Date()
date.setTime(date.getTime() + 24 * 60 * 60 * 1000)
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hsm = ' 08:30:00'
month = month < 10 ? '0' + month : month
day = day < 10 ? '0' + day : day
var time1 = year + '-' + month + '-' + day + hsm
time[1] = time1
date = new Date(date.getTime() - 24 * 60 * 60 * 1000 * subDay)
var lYear = date.getFullYear()
var lMonth = date.getMonth() + 1
var lDay = date.getDate()
lMonth = lMonth < 10 ? '0' + lMonth : lMonth
lDay = lDay < 10 ? '0' + lDay : lDay
var time2 = lYear + '-' + lMonth + '-' + lDay + hsm
time[0] = time2
return time
}
export function setRangeTime(subDay, isNeedTime = true) {
var time = []
var date = new Date()
var year = date.getFullYear()
var month = date.getMonth() + 1
var day = date.getDate()
var hsm = ' 08:30:00'
month = month < 10 ? '0' + month : month
day = day < 10 ? '0' + day : day
var time1 = year + '-' + month + '-' + day + (isNeedTime? hsm: '')
time[0] = time1
date = new Date(date.getTime() + 24 * 60 * 60 * 1000 * subDay)
var lYear = date.getFullYear()
var lMonth = date.getMonth() + 1
var lDay = date.getDate()
lMonth = lMonth < 10 ? '0' + lMonth : lMonth
lDay = lDay < 10 ? '0' + lDay : lDay
var time2 = lYear + '-' + lMonth + '-' + lDay + (isNeedTime? hsm: '')
time[1] = time2
return time
}
export function checkDate(startTime, endTime, days = 1) {
if (!startTime || !endTime) return
if (new Date(endTime).getTime() - new Date(startTime).getTime() > 60 * 60 * 24 * 1000 * days) {
return true
} else return false
}
// 区域打印方法, 传入参数是 element id
let printAreaCount = 0
function printArea(ele) {
const printElement = document.getElementById(ele)
if (!printElement) {
throw new Error(`didn't find this element "#${ele}"`)
}
const idPrefix = 'printArea_'
removePrintArea(idPrefix + printAreaCount)
printAreaCount++
const iframeId = idPrefix + printAreaCount
const iframeStyle = 'position:absolute;width:0px;height:0px;left:-500px;top:-500px;'
const iframe = document.createElement('IFRAME')
iframe.setAttribute('id', iframeId)
iframe.setAttribute('style', iframeStyle)
document.body.appendChild(iframe)
const doc = iframe.contentWindow.document
doc.open()
let css = ''
const links = Array.from(document.querySelectorAll('head>link')).filter(link => link.getAttribute('rel').toLowerCase() === 'stylesheet')
links.forEach(link => {
css += link.outerHTML
})
const styles = Array.from(document.querySelectorAll('head>style'))
styles.forEach(style => {
css += style.outerHTML
})
doc.write(css + printElement.outerHTML)
doc.close()
iframe.onload = () => {
const frameWindow = iframe.contentWindow
frameWindow.focus()
frameWindow.print()
}
}
function removePrintArea(id) {
const iframe = document.getElementById(id)
iframe && iframe.parentNode.removeChild(iframe)
}
export default printArea
import Vue from 'vue'
import { Loading } from 'element-ui';
let needLoadingRequestCount = 0; //当前正在请求的数量
let loadingInstance;
export function showLoading() {
let main = document.querySelector('body')
if (main) {
if (needLoadingRequestCount === 0 && !loadingInstance) {
loadingInstance = Loading.service({ background:"rgba(0, 0, 0, 0.8)",customClass:"Loading",text:"数据加载中..." });
}
needLoadingRequestCount++;
}
}
export function closeLoading() {
Vue.nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
needLoadingRequestCount--;
needLoadingRequestCount = Math.max(needLoadingRequestCount, 0); // 保证大于等于0
if (needLoadingRequestCount === 0) {
if (loadingInstance) {
hideLoading()
}
}
});
}
function hideLoading() {
loadingInstance.close();
loadingInstance = null;
}
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'lib/main.js'),
name: 'LayoutLib',
fileName: (format) => `layout-lib.${format}.js`
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
// into your library
external: ['vue'],
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
vue: 'Vue'
}
}
}
},
server: {
host: '0.0.0.0',
port: '4000',
},
css: {
devSourcemap: true
},
plugins: [
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
symbolId: 'icon-[dir]-[name]'
}),
createVuePlugin({
jsx: true
}),
],
define: {
__APP_VERSION__: JSON.stringify(new Date().toLocaleString())
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'~@': path.resolve(__dirname, './src'),
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
})
'use strict'
import path from 'path'
module.exports = {
context: path.resolve(__dirname, './'),
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': path.resolve(__dirname, 'src')
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment