mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-ui.git
synced 2026-11-06 17:09:08 +08:00
refactor(axios): 优化HTTP请求拦截器和错误处理机制
- 移除调试用的console.log语句 - 调整表格列对齐方式,将操作列从居中改为右对齐 - 添加搜索表单功能,包括账单号、店铺名称、生成时间等筛选条件 - 重构axios拦截器逻辑,简化错误处理流程 - 实现统一的token刷新机制,使用单例模式避免重复请求 - 优化防抖函数实现,提高性能表现 - 添加401和403状态码的特殊处理逻辑 - 统一错误提示信息的显示方式 - 优化表格列宽度设置,调整金额相关列的显示效果 - 删除未使用的组件文件和样式代码 - 移除调试相关的代码和注释 - 优化图标组件的导入方式,使用markRaw包装 - 优化热词统计图表的数据显示逻辑,添加空数据提示
This commit is contained in:
@@ -24,16 +24,13 @@
|
||||
"hls.js": "^1.6.16",
|
||||
"js-cookie": "^2.2.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"price-color": "1.0.2",
|
||||
"sass": "^1.63.6",
|
||||
"sass-loader": "^10.4.1",
|
||||
"sockjs-client": "^1.4.0",
|
||||
"swiper": "^6.3.5",
|
||||
"uuid": "^8.3.2",
|
||||
"vue": "^3.5.35",
|
||||
"vue-awesome-swiper": "^4.1.1",
|
||||
"vue-i18n": "^9.10.2",
|
||||
"vue-json-excel": "^0.3.0",
|
||||
"vue-qr": "^5.0.3",
|
||||
"vue-router": "^4.6.4",
|
||||
"vuedraggable": "^4.1.0",
|
||||
|
||||
63
manager/pnpm-lock.yaml
generated
63
manager/pnpm-lock.yaml
generated
@@ -46,9 +46,6 @@ importers:
|
||||
nprogress:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
price-color:
|
||||
specifier: 1.0.2
|
||||
version: 1.0.2
|
||||
sass:
|
||||
specifier: ^1.63.6
|
||||
version: 1.101.0
|
||||
@@ -67,15 +64,9 @@ importers:
|
||||
vue:
|
||||
specifier: ^3.5.35
|
||||
version: 3.5.39
|
||||
vue-awesome-swiper:
|
||||
specifier: ^4.1.1
|
||||
version: 4.1.1(swiper@6.8.4)(vue@3.5.39)
|
||||
vue-i18n:
|
||||
specifier: ^9.10.2
|
||||
version: 9.14.5(vue@3.5.39)
|
||||
vue-json-excel:
|
||||
specifier: ^0.3.0
|
||||
version: 0.3.0
|
||||
vue-qr:
|
||||
specifier: ^5.0.3
|
||||
version: 5.0.3(vue@3.5.39)
|
||||
@@ -1148,9 +1139,6 @@ packages:
|
||||
'@vue/compiler-dom@3.5.39':
|
||||
resolution: {integrity: sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==}
|
||||
|
||||
'@vue/compiler-sfc@2.7.16':
|
||||
resolution: {integrity: sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==}
|
||||
|
||||
'@vue/compiler-sfc@3.5.39':
|
||||
resolution: {integrity: sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==}
|
||||
|
||||
@@ -2036,9 +2024,6 @@ packages:
|
||||
resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
downloadjs@1.4.7:
|
||||
resolution: {integrity: sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==}
|
||||
|
||||
dplayer@1.27.1:
|
||||
resolution: {integrity: sha512-2laBMXs5V1B9zPwJ7eAIw/OBo+Xjvy03i4GHTk3Cg+IWbrq8rKMFO0fFr6ClAYotYOCcFGOvaJDkOZcgKllsCA==}
|
||||
|
||||
@@ -2313,7 +2298,7 @@ packages:
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
|
||||
globby@11.1.0:
|
||||
resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
|
||||
@@ -3322,9 +3307,6 @@ packages:
|
||||
pretty-error@4.0.0:
|
||||
resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==}
|
||||
|
||||
price-color@1.0.2:
|
||||
resolution: {integrity: sha512-QkgrM0RxjAB+yxcRVuVTzgkxoYoGTAKbxIzJAZFFbActqKC4n9U4eDFWTpKQ+0FklRdZCnKenSPe+upfpe8+PQ==}
|
||||
|
||||
process-nextick-args@2.0.1:
|
||||
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
|
||||
|
||||
@@ -3913,13 +3895,6 @@ packages:
|
||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
vue-awesome-swiper@4.1.1:
|
||||
resolution: {integrity: sha512-50um10t6N+lJaORkpwSi1wWuMmBI1sgFc9Znsi5oUykw2cO5DzLaBHcO2JNX21R+Ue4TGoIJDhhxjBHtkFrTEQ==}
|
||||
engines: {node: '>=8'}
|
||||
peerDependencies:
|
||||
swiper: ^5.2.0
|
||||
vue: 2.x
|
||||
|
||||
vue-cli-plugin-style-resources-loader@0.1.5:
|
||||
resolution: {integrity: sha512-LluhjWTZmpGl3tiXg51EciF+T70IN/9t6UvfmgluJBqxbrb6OV9i7L5lTd+OKtcTeghDkhcBmYhtTxxU4w/8sQ==}
|
||||
|
||||
@@ -3936,9 +3911,6 @@ packages:
|
||||
peerDependencies:
|
||||
vue: ^3.0.0
|
||||
|
||||
vue-json-excel@0.3.0:
|
||||
resolution: {integrity: sha512-FrSh0tVUpw4K+ilLO8g0Qp52eFJw/hkk3rZPTEKo9qVkJgVfQtZwzj3UWc5ACYxA3jLk9HtjK+f9xKHCN4Kgag==}
|
||||
|
||||
vue-loader@15.11.1:
|
||||
resolution: {integrity: sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==}
|
||||
peerDependencies:
|
||||
@@ -3986,10 +3958,6 @@ packages:
|
||||
vue-template-es2015-compiler@1.9.1:
|
||||
resolution: {integrity: sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==}
|
||||
|
||||
vue@2.7.16:
|
||||
resolution: {integrity: sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==}
|
||||
deprecated: Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.
|
||||
|
||||
vue@3.5.39:
|
||||
resolution: {integrity: sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==}
|
||||
peerDependencies:
|
||||
@@ -5608,14 +5576,6 @@ snapshots:
|
||||
'@vue/compiler-core': 3.5.39
|
||||
'@vue/shared': 3.5.39
|
||||
|
||||
'@vue/compiler-sfc@2.7.16':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.7
|
||||
postcss: 8.5.15
|
||||
source-map: 0.6.1
|
||||
optionalDependencies:
|
||||
prettier: 2.8.8
|
||||
|
||||
'@vue/compiler-sfc@3.5.39':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.7
|
||||
@@ -6486,8 +6446,6 @@ snapshots:
|
||||
|
||||
dotenv@10.0.0: {}
|
||||
|
||||
downloadjs@1.4.7: {}
|
||||
|
||||
dplayer@1.27.1:
|
||||
dependencies:
|
||||
axios: 1.2.3
|
||||
@@ -7694,11 +7652,6 @@ snapshots:
|
||||
lodash: 4.18.1
|
||||
renderkid: 3.0.0
|
||||
|
||||
price-color@1.0.2:
|
||||
dependencies:
|
||||
core-js: 3.49.0
|
||||
vue: 2.7.16
|
||||
|
||||
process-nextick-args@2.0.1: {}
|
||||
|
||||
progress-webpack-plugin@1.0.16(webpack@5.108.4(postcss@8.5.15)):
|
||||
@@ -8290,11 +8243,6 @@ snapshots:
|
||||
|
||||
vary@1.1.2: {}
|
||||
|
||||
vue-awesome-swiper@4.1.1(swiper@6.8.4)(vue@3.5.39):
|
||||
dependencies:
|
||||
swiper: 6.8.4
|
||||
vue: 3.5.39
|
||||
|
||||
vue-cli-plugin-style-resources-loader@0.1.5: {}
|
||||
|
||||
vue-component-type-helpers@3.3.5: {}
|
||||
@@ -8308,10 +8256,6 @@ snapshots:
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.39
|
||||
|
||||
vue-json-excel@0.3.0:
|
||||
dependencies:
|
||||
downloadjs: 1.4.7
|
||||
|
||||
vue-loader@15.11.1(@vue/compiler-sfc@3.5.39)(css-loader@6.11.0(webpack@5.108.4(postcss@8.5.15)))(lodash@4.18.1)(webpack@5.108.4(postcss@8.5.15)):
|
||||
dependencies:
|
||||
'@vue/component-compiler-utils': 3.3.0(lodash@4.18.1)
|
||||
@@ -8404,11 +8348,6 @@ snapshots:
|
||||
|
||||
vue-template-es2015-compiler@1.9.1: {}
|
||||
|
||||
vue@2.7.16:
|
||||
dependencies:
|
||||
'@vue/compiler-sfc': 2.7.16
|
||||
csstype: 3.2.3
|
||||
|
||||
vue@3.5.39:
|
||||
dependencies:
|
||||
'@vue/compiler-dom': 3.5.39
|
||||
|
||||
@@ -43,7 +43,6 @@ export default {
|
||||
watch: {
|
||||
changed: {
|
||||
handler(val) {
|
||||
console.log(val,'changed')
|
||||
this.$emit("selectedLink", val[0]); //因为是单选,所以直接返回第一个
|
||||
},
|
||||
deep: true
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
// text
|
||||
@prefixCls: zk-checkbox;
|
||||
// color
|
||||
@border: #dddee1;
|
||||
@hoverBorder: #bcbcbc;
|
||||
@blue: #2d8cf0;
|
||||
|
||||
.@{prefixCls}-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.@{prefixCls} {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @hoverBorder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}__inner {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: 1px solid @border;
|
||||
border-radius: 2px;
|
||||
background-color: #ffffff;
|
||||
transition: border-color .2s ease-in-out,background-color .2s ease-in-out;
|
||||
&::after {
|
||||
content: "";
|
||||
display: table;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 4px;
|
||||
border: 2px solid #fff;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
transform: rotate(45deg) scale(0);
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--indeterminate {
|
||||
.@{prefixCls}__inner {
|
||||
background-color: @blue;
|
||||
border-color: @blue;
|
||||
&::after {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 1px;
|
||||
transform: scale(1);
|
||||
position: absolute;
|
||||
left: 2px;
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--checked {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @blue;
|
||||
background-color: @blue;
|
||||
&::after {
|
||||
content: "";
|
||||
display: table;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 4px;
|
||||
border: 2px solid #ffffff;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
transform: rotate(45deg) scale(1);
|
||||
transition: all .2s ease-in-out;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--disabled {
|
||||
cursor: not-allowed;
|
||||
.@{prefixCls}__inner {
|
||||
background-color: #f3f3f3;
|
||||
border-color: @border;
|
||||
&::after {
|
||||
animation-name: none;
|
||||
border-color: #ccc;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
.@{prefixCls}__inner {
|
||||
border-color: @border;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<template lang="html">
|
||||
<label :class="`${prefixCls}-wrapper`">
|
||||
<span :class="checkboxClass">
|
||||
<span
|
||||
:class="`${prefixCls}__inner`"
|
||||
@click="toggle"></span>
|
||||
</span>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'zk-checkbox',
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
indeterminate: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
prefixCls: 'zk-checkbox',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
checkboxClass() {
|
||||
return [
|
||||
`${this.prefixCls}`,
|
||||
{
|
||||
[`${this.prefixCls}--disabled`]: this.disabled,
|
||||
[`${this.prefixCls}--checked`]: this.value,
|
||||
[`${this.prefixCls}--indeterminate`]: this.indeterminate,
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggle() {
|
||||
if (this.disabled) {
|
||||
return false;
|
||||
}
|
||||
const value = !this.value;
|
||||
this.$emit('input', value);
|
||||
return this.$emit('on-change', value);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped src="./Checkbox.less"></style>
|
||||
@@ -1,170 +0,0 @@
|
||||
@import "./font/iconfont";
|
||||
|
||||
// text
|
||||
@prefixCls: zk-table;
|
||||
// color
|
||||
@black: #515a6e;
|
||||
@white: #ffffff;
|
||||
@border: #e9eaec;
|
||||
@hoverRow: #ebf7ff;
|
||||
@backgroundRow: #f8f8f9;
|
||||
|
||||
.@{prefixCls} {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: @white;
|
||||
border: 1px solid @border;
|
||||
font-size: 14px;
|
||||
line-height: 26px;
|
||||
color: @black;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-cell {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.@{prefixCls}__cell-inner {
|
||||
padding: 0px 18px;
|
||||
}
|
||||
|
||||
.@{prefixCls}-default {
|
||||
font-size: 14px;
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 48px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}-small {
|
||||
font-size: 12px;
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 36px !important;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 40px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}-large {
|
||||
font-size: 16px;
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 43px !important;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 60px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-wrapper,
|
||||
.@{prefixCls}__footer-wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-wrapper {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.@{prefixCls}__header,
|
||||
.@{prefixCls}__body,
|
||||
.@{prefixCls}__footer {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-row {
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
background-color: @backgroundRow;
|
||||
border-bottom: 1px solid @border;
|
||||
}
|
||||
|
||||
.@{prefixCls}__footer-row {
|
||||
height: 40px;
|
||||
box-sizing: border-box;
|
||||
background-color: @white;
|
||||
border-top: 1px solid @border;
|
||||
}
|
||||
|
||||
.@{prefixCls}__body-row {
|
||||
height: 48px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:not(:first-of-type) {
|
||||
border-top: 1px solid @border;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}__header-cell,
|
||||
.@{prefixCls}__body-cell,
|
||||
.@{prefixCls}__footer-cell {
|
||||
box-sizing: border-box;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
word-break: break-all;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.@{prefixCls}--firstProp-header-inner {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.@{prefixCls}--empty-row {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.@{prefixCls}--empty-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.@{prefixCls}--center-cell {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.@{prefixCls}--right-cell {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.@{prefixCls}--stripe-row {
|
||||
background-color: @backgroundRow;
|
||||
}
|
||||
|
||||
.@{prefixCls}--row-hover {
|
||||
background-color: @hoverRow;
|
||||
}
|
||||
|
||||
.@{prefixCls}--border-cell {
|
||||
&:not(:last-of-type) {
|
||||
border-right: 1px solid @border;
|
||||
}
|
||||
}
|
||||
|
||||
.@{prefixCls}--tree-icon {
|
||||
margin-right: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.@{prefixCls}--expand-inner {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: transform .2s ease-in-out;
|
||||
}
|
||||
|
||||
.@{prefixCls}--expanded-inner {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.@{prefixCls}--expand-content {
|
||||
padding: 20px;
|
||||
}
|
||||
@@ -1,401 +0,0 @@
|
||||
<template lang="html">
|
||||
<div
|
||||
v-if="columns.length > 0"
|
||||
ref="table"
|
||||
v-loading="loading"
|
||||
:class="[prefixCls, `${prefixCls}-${size}`, tableClass]">
|
||||
<div
|
||||
v-show="showHeader"
|
||||
ref="header-wrapper"
|
||||
:class="`${prefixCls}__header-wrapper`"
|
||||
@mousewheel="handleEvent('header', $event)">
|
||||
<table-header
|
||||
ref="table-header">
|
||||
</table-header>
|
||||
</div>
|
||||
<div
|
||||
ref="body-wrapper"
|
||||
:style="bodyWrapperStyle"
|
||||
:class="`${prefixCls}__body-wrapper`"
|
||||
@scroll="handleEvent('body', $event)">
|
||||
<table-body
|
||||
ref="table-body"
|
||||
:class="bodyClass">
|
||||
</table-body>
|
||||
</div>
|
||||
<div
|
||||
v-show="showSummary && data.length > 0"
|
||||
ref="footer-wrapper"
|
||||
:class="`${prefixCls}__footer-wrapper`"
|
||||
@mousewheel="handleEvent('footer', $event)">
|
||||
<table-footer
|
||||
ref="table-footer">
|
||||
</table-footer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TableHeader from "./TableHeader";
|
||||
import TableBody from "./TableBody";
|
||||
import TableFooter from "./TableFooter";
|
||||
import { mixins, scrollBarWidth as getSbw } from "./utils";
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
/* eslint-disable no-param-reassign */
|
||||
|
||||
// function getBodyData(data, isTreeType, childrenProp, isFold, level = 1) {
|
||||
function getBodyData(
|
||||
primaryKey,
|
||||
oldBodyData,
|
||||
data,
|
||||
isTreeType,
|
||||
childrenProp,
|
||||
isFold,
|
||||
parentFold,
|
||||
level = 1
|
||||
) {
|
||||
let bodyData = [];
|
||||
data.forEach((row, index) => {
|
||||
const children = row[childrenProp];
|
||||
const childrenLen =
|
||||
Object.prototype.toString.call(children).slice(8, -1) === "Array"
|
||||
? children.length
|
||||
: 0;
|
||||
let curIsFold = isFold;
|
||||
if (
|
||||
isFold &&
|
||||
typeof primaryKey === "string" &&
|
||||
Array.isArray(oldBodyData)
|
||||
) {
|
||||
for (let i = 0; i < oldBodyData.length; i++) {
|
||||
const oldRow = oldBodyData[i];
|
||||
if (oldRow[primaryKey] === row[primaryKey]) {
|
||||
if ("_isFold" in oldRow) {
|
||||
curIsFold = oldRow._isFold;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bodyData.push({
|
||||
_isHover: false,
|
||||
_isExpanded: false,
|
||||
_isChecked: false,
|
||||
_level: level,
|
||||
// _isHide: isFold ? level !== 1 : false,
|
||||
// _isFold: isFold,
|
||||
_isHide: level !== 1 ? isFold && parentFold : false,
|
||||
_isFold: isFold && curIsFold,
|
||||
_childrenLen: childrenLen,
|
||||
_normalIndex: index + 1,
|
||||
...row
|
||||
});
|
||||
if (isTreeType) {
|
||||
if (childrenLen > 0) {
|
||||
// bodyData = bodyData.concat(getBodyData(children, true, childrenProp, isFold, level + 1));
|
||||
bodyData = bodyData.concat(
|
||||
getBodyData(
|
||||
primaryKey,
|
||||
oldBodyData,
|
||||
children,
|
||||
true,
|
||||
childrenProp,
|
||||
isFold,
|
||||
curIsFold,
|
||||
level + 1
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
return bodyData;
|
||||
}
|
||||
|
||||
function initialState(table, expandKey) {
|
||||
return {
|
||||
bodyHeight: "auto",
|
||||
firstProp: expandKey || (table.columns[0] && table.columns[0].key),
|
||||
// bodyData: getBodyData(table.data, table.treeType, table.childrenProp, table.isFold),
|
||||
bodyData: getBodyData(
|
||||
table.primaryKey,
|
||||
table.bodyData,
|
||||
table.data,
|
||||
table.treeType,
|
||||
table.childrenProp,
|
||||
table.isFold,
|
||||
false
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
function initialColumns(table, clientWidth) {
|
||||
let columnsWidth = 0;
|
||||
const minWidthColumns = [];
|
||||
const otherColumns = [];
|
||||
const columns = table.columns.concat();
|
||||
if (table.expandType) {
|
||||
columns.unshift({
|
||||
width: "50"
|
||||
});
|
||||
}
|
||||
if (table.selectable) {
|
||||
columns.unshift({
|
||||
width: "50"
|
||||
});
|
||||
}
|
||||
if (table.showIndex) {
|
||||
columns.unshift({
|
||||
width: "50px",
|
||||
key: "_normalIndex",
|
||||
title: table.indexText
|
||||
});
|
||||
}
|
||||
columns.forEach((column, index) => {
|
||||
let width = "";
|
||||
let minWidth = "";
|
||||
if (!column.width) {
|
||||
if (column.minWidth) {
|
||||
minWidth =
|
||||
typeof column.minWidth === "number"
|
||||
? column.minWidth
|
||||
: parseInt(column.minWidth, 10);
|
||||
} else {
|
||||
minWidth = 80;
|
||||
}
|
||||
minWidthColumns.push({
|
||||
...column,
|
||||
minWidth,
|
||||
_index: index
|
||||
});
|
||||
} else {
|
||||
width =
|
||||
typeof column.width === "number"
|
||||
? column.width
|
||||
: parseInt(column.width, 10);
|
||||
otherColumns.push({
|
||||
...column,
|
||||
width,
|
||||
_index: index
|
||||
});
|
||||
}
|
||||
columnsWidth += minWidth || width;
|
||||
});
|
||||
const scrollBarWidth = getSbw();
|
||||
const totalWidth = columnsWidth + scrollBarWidth;
|
||||
const isScrollX = totalWidth > clientWidth;
|
||||
if (!isScrollX) {
|
||||
const extraWidth = clientWidth - totalWidth;
|
||||
const averageExtraWidth = Math.floor(extraWidth / minWidthColumns.length);
|
||||
minWidthColumns.forEach(column => {
|
||||
column.computedWidth = column.minWidth + averageExtraWidth;
|
||||
});
|
||||
}
|
||||
const tableColumns = otherColumns.concat(minWidthColumns);
|
||||
tableColumns.sort((a, b) => a._index - b._index);
|
||||
return tableColumns;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "TreeTable",
|
||||
mixins: [mixins],
|
||||
components: {
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableFooter
|
||||
},
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
size: {
|
||||
default() {
|
||||
return !this.$IVIEW || this.$IVIEW.size === ""
|
||||
? "default"
|
||||
: this.$IVIEW.size;
|
||||
}
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxHeight: {
|
||||
type: [String, Number],
|
||||
default: "auto"
|
||||
},
|
||||
stripe: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
treeType: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
childrenProp: {
|
||||
type: String,
|
||||
default: "children"
|
||||
},
|
||||
isFold: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
expandType: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selectable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
selectType: {
|
||||
type: String,
|
||||
default: "checkbox"
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: "暂无数据"
|
||||
},
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
showIndex: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
indexText: {
|
||||
type: String,
|
||||
default: "#"
|
||||
},
|
||||
showSummary: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
sumText: {
|
||||
type: String,
|
||||
default: "合计"
|
||||
},
|
||||
primaryKey: String,
|
||||
summaryMethod: Function,
|
||||
showRowHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
rowKey: Function,
|
||||
rowClassName: [String, Function],
|
||||
cellClassName: [String, Function],
|
||||
rowStyle: [Object, Function],
|
||||
cellStyle: [Object, Function],
|
||||
expandKey: String
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
treeTableRoot: this,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
computedWidth: "",
|
||||
computedHeight: "",
|
||||
tableColumns: [],
|
||||
...initialState(this, this.expandKey)
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
bodyWrapperStyle() {
|
||||
return {
|
||||
height: this.bodyHeight
|
||||
};
|
||||
},
|
||||
tableClass() {
|
||||
return {
|
||||
[`${this.prefixCls}--border`]: this.border
|
||||
};
|
||||
},
|
||||
bodyClass() {
|
||||
return {
|
||||
[`${this.prefixCls}--stripe`]: this.stripe
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleEvent(type, $event) {
|
||||
this.validateType(type, ["header", "body", "footer"], "handleEvent");
|
||||
const eventType = $event.type;
|
||||
if (eventType === "scroll") {
|
||||
this.$refs["header-wrapper"].scrollLeft = $event.target.scrollLeft;
|
||||
this.$refs["footer-wrapper"].scrollLeft = $event.target.scrollLeft;
|
||||
}
|
||||
if (eventType === "mousewheel") {
|
||||
const deltaX = $event.deltaX;
|
||||
const $body = this.$refs["body-wrapper"];
|
||||
if (deltaX > 0) {
|
||||
$body.scrollLeft += 10;
|
||||
} else {
|
||||
$body.scrollLeft -= 10;
|
||||
}
|
||||
}
|
||||
return this.$emit(`${type}-${eventType}`, $event);
|
||||
},
|
||||
// computedWidth, computedHeight, tableColumns
|
||||
measure() {
|
||||
this.$nextTick(() => {
|
||||
const { clientWidth, clientHeight } = this.$el;
|
||||
this.computedWidth = clientWidth + 2;
|
||||
this.computedHeight = clientHeight + 2;
|
||||
|
||||
const maxHeight = parseInt(this.maxHeight, 10);
|
||||
if (this.maxHeight !== "auto" && this.computedHeight > maxHeight) {
|
||||
this.bodyHeight = `${maxHeight - 83}px`;
|
||||
}
|
||||
this.tableColumns = initialColumns(this, clientWidth);
|
||||
});
|
||||
},
|
||||
getCheckedProp(key = "index") {
|
||||
if (!this.selectable) {
|
||||
return [];
|
||||
}
|
||||
const checkedIndexs = [];
|
||||
this.bodyData.forEach((item, index) => {
|
||||
if (item._isChecked) {
|
||||
if (key === "index") {
|
||||
checkedIndexs.push(index);
|
||||
} else {
|
||||
checkedIndexs.push(item[key]);
|
||||
}
|
||||
}
|
||||
});
|
||||
return checkedIndexs;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$props: {
|
||||
deep: true,
|
||||
handler() {
|
||||
Object.assign(this.$data, initialState(this, this.expandKey));
|
||||
}
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
this.measure();
|
||||
},
|
||||
mounted() {
|
||||
this.measure();
|
||||
window.addEventListener("resize", this.measure);
|
||||
},
|
||||
beforeUnmount() {
|
||||
window.removeEventListener("resize", this.measure);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" src="./Table.less"></style>
|
||||
@@ -1,355 +0,0 @@
|
||||
import Checkbox from '../Checkbox/Checkbox'; // eslint-disable-line
|
||||
// import Radio from '../Radio/Radio'; // eslint-disable-line
|
||||
import { mixins } from './utils';
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default {
|
||||
name: 'TreeTable__body',
|
||||
mixins: [mixins],
|
||||
inject: {
|
||||
treeTableRoot: { default: null },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
radioSelectedIndex: -1,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
table() {
|
||||
if (this.treeTableRoot) return this.treeTableRoot;
|
||||
let parent = this.$parent;
|
||||
while (parent) {
|
||||
if (parent.$options && parent.$options.name === 'TreeTable') return parent;
|
||||
parent = parent.$parent;
|
||||
}
|
||||
return this.$parent;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleStatus(type, row, rowIndex, value) {
|
||||
this.validateType(type, ['Expanded', 'Checked', 'Hide', 'Fold'], 'toggleStatus', false);
|
||||
const target = this.table.bodyData[rowIndex];
|
||||
this.table.bodyData.splice(rowIndex, 1, {
|
||||
...target,
|
||||
[`_is${type}`]: typeof value === 'undefined' ? !row[`_is${type}`] : value,
|
||||
});
|
||||
},
|
||||
getChildrenIndex(parentLevel, parentIndex, careFold = true) {
|
||||
const data = this.table.bodyData;
|
||||
let childrenIndex = [];
|
||||
for (let i = parentIndex + 1; i < data.length; i++) {
|
||||
if (data[i]._level <= parentLevel) break;
|
||||
if (data[i]._level - 1 === parentLevel) {
|
||||
childrenIndex.push(i);
|
||||
}
|
||||
}
|
||||
const len = childrenIndex.length; // important!!!
|
||||
if (len > 0) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
const childData = data[childrenIndex[i]];
|
||||
if (
|
||||
childData._childrenLen &&
|
||||
(!careFold || (careFold && !childData._isFold))
|
||||
) {
|
||||
childrenIndex = childrenIndex.concat(
|
||||
this.getChildrenIndex(childData._level, childrenIndex[i], careFold));
|
||||
}
|
||||
}
|
||||
}
|
||||
return childrenIndex;
|
||||
},
|
||||
handleEvent($event, type, data, others) {
|
||||
const certainType = this.validateType(type, ['cell', 'row', 'checkbox', 'icon', 'radio'], 'handleEvent');
|
||||
const eventType = $event ? $event.type : '';
|
||||
const { row, rowIndex, column, columnIndex } = data;
|
||||
const latestData = this.table.bodyData;
|
||||
// Checkbox
|
||||
if (certainType.checkbox) {
|
||||
const { isChecked } = others;
|
||||
this.toggleStatus('Checked', row, rowIndex, isChecked);
|
||||
if (row._childrenLen > 0) {
|
||||
const childrenIndex = this.getChildrenIndex(row._level, rowIndex, false);
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
this.toggleStatus('Checked', latestData[childrenIndex[i]], childrenIndex[i], isChecked);
|
||||
}
|
||||
}
|
||||
return this.table.$emit('checkbox-click', latestData[rowIndex], column, columnIndex, $event);
|
||||
}
|
||||
// Radio
|
||||
if (certainType.radio) {
|
||||
this.radioSelectedIndex = rowIndex;
|
||||
return this.table.$emit('radio-click', { row, rowIndex, column, columnIndex, $event });
|
||||
}
|
||||
// Tree's icon
|
||||
if (certainType.icon) {
|
||||
$event.stopPropagation();
|
||||
this.toggleStatus('Fold', row, rowIndex);
|
||||
const childrenIndex = this.getChildrenIndex(row._level, rowIndex);
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
this.toggleStatus('Hide', latestData[childrenIndex[i]], childrenIndex[i]);
|
||||
}
|
||||
return this.table.$emit('tree-icon-click', latestData[rowIndex], column, columnIndex, $event);
|
||||
}
|
||||
if (certainType.cell && eventType === 'click') {
|
||||
// 点击扩展单元格
|
||||
if (this.isExpandCell(this.table, columnIndex)) {
|
||||
this.toggleStatus('Expanded', row, rowIndex);
|
||||
return this.table.$emit('expand-cell-click', latestData[rowIndex], column, columnIndex, $event);
|
||||
}
|
||||
}
|
||||
// 行:Hover
|
||||
if (certainType.row && (eventType === 'mouseenter' || eventType === 'mouseleave')) {
|
||||
const { hover } = others;
|
||||
const target = latestData[rowIndex];
|
||||
latestData.splice(rowIndex, 1, {
|
||||
...target,
|
||||
_isHover: hover,
|
||||
});
|
||||
}
|
||||
if (certainType.row && others && others.clickRow && certainType.radio) {
|
||||
this.radioSelectedIndex = rowIndex;
|
||||
return this.table.$emit('radio-click', { row, rowIndex, column, columnIndex, $event });
|
||||
}
|
||||
if (certainType.cell) {
|
||||
return this.table.$emit(`${type}-${eventType}`, latestData[rowIndex], rowIndex, column, columnIndex, $event);
|
||||
}
|
||||
return this.table.$emit(`${type}-${eventType}`, latestData[rowIndex], rowIndex, $event);
|
||||
},
|
||||
},
|
||||
render() {
|
||||
// key
|
||||
// function getKey(row, rowIndex) {
|
||||
// const rowKey = this.table.rowKey;
|
||||
// if (rowKey) {
|
||||
// return rowKey.call(null, row, rowIndex);
|
||||
// }
|
||||
// return rowIndex;
|
||||
// }
|
||||
|
||||
// style
|
||||
function getStyle(type, row, rowIndex, column, columnIndex) {
|
||||
const certainType = this.validateType(type, ['cell', 'row'], 'getStyle');
|
||||
const style = this.table[`${type}Style`];
|
||||
if (typeof style === 'function') {
|
||||
if (certainType.row) {
|
||||
return style.call(null, row, rowIndex);
|
||||
}
|
||||
if (certainType.cell) {
|
||||
return style.call(null, row, rowIndex, column, columnIndex);
|
||||
}
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
// className
|
||||
function getClassName(type, row, rowIndex, column, columnIndex) {
|
||||
const certainType = this.validateType(type, ['cell', 'row', 'inner'], 'getClassName');
|
||||
const classList = [];
|
||||
if (column && column.key == "_normalIndex") {
|
||||
classList.push(`${this.prefixCls}--center-cell`);
|
||||
}
|
||||
// console.log(certainType.inner)
|
||||
if (certainType.row || certainType.cell) {
|
||||
const className = this.table[`${type}ClassName`];
|
||||
if (typeof className === 'string') {
|
||||
classList.push(className);
|
||||
} else if (typeof className === 'function') {
|
||||
if (certainType.row) {
|
||||
classList.push(className.call(null, row, rowIndex) || '');
|
||||
}
|
||||
if (certainType.cell) {
|
||||
classList.push(className.call(null, row, rowIndex, column, columnIndex) || '');
|
||||
}
|
||||
}
|
||||
if (certainType.row) {
|
||||
classList.push(`${this.prefixCls}__body-row`);
|
||||
if (this.table.stripe && rowIndex % 2 !== 0) {
|
||||
classList.push(`${this.prefixCls}--stripe-row`);
|
||||
}
|
||||
if (this.table.showRowHover && row._isHover) {
|
||||
classList.push(`${this.prefixCls}--row-hover`);
|
||||
}
|
||||
}
|
||||
if (certainType.cell) {
|
||||
classList.push(`${this.prefixCls}__body-cell`);
|
||||
if (this.table.border) {
|
||||
classList.push(`${this.prefixCls}--border-cell`);
|
||||
}
|
||||
const align = column.align;
|
||||
if (['center', 'right'].indexOf(align) > -1) {
|
||||
classList.push(`${this.prefixCls}--${align}-cell`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (certainType.inner) {
|
||||
classList.push(`${this.prefixCls}__cell-inner`);
|
||||
if (this.isExpandCell(this.table, columnIndex)) {
|
||||
classList.push(`${this.prefixCls}--expand-inner`);
|
||||
if (row._isExpanded) {
|
||||
classList.push(`${this.prefixCls}--expanded-inner`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return classList.join(' ');
|
||||
}
|
||||
|
||||
// Vue 3:scoped slot 合并到 $slots
|
||||
function renderTemplateSlot(table, slotName, scope) {
|
||||
if (!table || !slotName) return '';
|
||||
const slots = table.$slots || {};
|
||||
let slot = slots[slotName];
|
||||
if (!slot && table.$scopedSlots && table.$scopedSlots[slotName]) {
|
||||
slot = table.$scopedSlots[slotName];
|
||||
}
|
||||
if (!slot) return '';
|
||||
return slot(scope);
|
||||
}
|
||||
|
||||
// 根据type渲染单元格Cell
|
||||
function renderCell(row, rowIndex, column, columnIndex) {
|
||||
if (!row || !column) return '';
|
||||
// ExpandType
|
||||
if (this.isExpandCell(this.table, columnIndex)) {
|
||||
return <i class='zk-icon zk-icon-angle-right'></i>;
|
||||
}
|
||||
// SelectionType's Checkbox
|
||||
if (this.isSelectionCell(this.table, columnIndex)) {
|
||||
let res = null;
|
||||
if (this.table.selectType === 'checkbox') {
|
||||
let allCheck;
|
||||
let childrenIndex;
|
||||
const hasChildren = row._childrenLen > 0;
|
||||
if (hasChildren) {
|
||||
childrenIndex = this.getChildrenIndex(row._level, rowIndex, false);
|
||||
allCheck = true;
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
if (!this.table.bodyData[childrenIndex[i]]._isChecked) {
|
||||
allCheck = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
allCheck = row._isChecked;
|
||||
}
|
||||
let indeterminate = false;
|
||||
if (hasChildren && !allCheck) {
|
||||
for (let i = 0; i < childrenIndex.length; i++) {
|
||||
if (this.table.bodyData[childrenIndex[i]]._isChecked) {
|
||||
indeterminate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// res = <Checkbox
|
||||
// indeterminate={indeterminate}
|
||||
// value={allCheck}
|
||||
// onOn-change={isChecked => this.handleEvent(null, 'checkbox', { row, rowIndex, column, columnIndex }, { isChecked })}>
|
||||
// </Checkbox>;
|
||||
} else {
|
||||
res = (
|
||||
<input
|
||||
type="radio"
|
||||
checked={this.radioSelectedIndex === rowIndex}
|
||||
onChange={() =>
|
||||
this.handleEvent(null, 'radio', { row, rowIndex, column, columnIndex })
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Tree's firstProp
|
||||
if (this.table.treeType && this.table.firstProp === column.key) {
|
||||
return <span
|
||||
class={`${this.prefixCls}--level-${row._level}-cell`}
|
||||
style={{
|
||||
marginLeft: `${(row._level - 1) * 24}px`,
|
||||
paddingLeft: row._childrenLen === 0 ? '20px' : '',
|
||||
}}>
|
||||
{row._childrenLen > 0 &&
|
||||
<i
|
||||
class={`${this.prefixCls}--tree-icon zk-icon zk-icon-${row._isFold ? 'plus' : 'minus'}-square-o`}
|
||||
on-click={$event => this.handleEvent($event, 'icon', { row, rowIndex, column, columnIndex }, { isFold: row._isFold })}></i>
|
||||
}
|
||||
{row[column.key] ? row[column.key] : ''}
|
||||
</span>;
|
||||
}
|
||||
// TreeType children's index
|
||||
if (this.table.showIndex && this.table.treeType && column.key === '_normalIndex' && row._level > 1) {
|
||||
return '';
|
||||
}
|
||||
if (column.type === undefined || column.type === 'custom') {
|
||||
return row[column.key];
|
||||
} else if (column.type === 'template') {
|
||||
return renderTemplateSlot.call(this, this.table, column.template, {
|
||||
row,
|
||||
rowIndex,
|
||||
column,
|
||||
columnIndex,
|
||||
});
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// Template
|
||||
return (
|
||||
<table cellspacing="0" cellpadding="0" border="0" class={`${this.prefixCls}__body`}>
|
||||
{/* <colgroup>
|
||||
{this.table.tableColumns.map(column =>
|
||||
<col width={column.computedWidth || column.minWidth || column.width}></col>)
|
||||
}
|
||||
</colgroup> */}
|
||||
<tbody>
|
||||
{ this.table.bodyData.length > 0
|
||||
? this.table.bodyData.map((row, rowIndex) =>
|
||||
[
|
||||
<tr
|
||||
v-show={!row._isHide}
|
||||
key={`table_row_${rowIndex}`}
|
||||
style={getStyle.call(this, 'row', row, rowIndex)}
|
||||
class={getClassName.call(this, 'row', row, rowIndex)}
|
||||
on-click={$event => this.handleEvent($event, 'row', { row, rowIndex }, { clickRow: true })}
|
||||
on-dblclick={$event => this.handleEvent($event, 'row', { row, rowIndex })}
|
||||
on-contextmenu={$event => this.handleEvent($event, 'row', { row, rowIndex })}
|
||||
on-mouseenter={$event => this.handleEvent($event, 'row', { row, rowIndex }, { hover: true })}
|
||||
on-mouseleave={$event => this.handleEvent($event, 'row', { row, rowIndex }, { hover: false })}>
|
||||
{ this.table.tableColumns.map((column, columnIndex) =>
|
||||
column.key ? <td
|
||||
style={getStyle.call(this, 'cell', row, rowIndex, column, columnIndex)}
|
||||
class={getClassName.call(this, 'cell', row, rowIndex, column, columnIndex)}
|
||||
on-click={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-dblclick={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-contextmenu={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-mouseenter={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}
|
||||
on-mouseleave={$event => this.handleEvent($event, 'cell', { row, rowIndex, column, columnIndex })}>
|
||||
<div class={getClassName.call(this, 'inner', row, rowIndex, column, columnIndex)}>
|
||||
{renderCell.call(this, row, rowIndex, column, columnIndex)}
|
||||
</div>
|
||||
</td>:"")
|
||||
}
|
||||
</tr>,
|
||||
this.table.expandType && row._isExpanded &&
|
||||
<tr
|
||||
key={rowIndex}
|
||||
class={`${this.prefixCls}__body-row ${this.prefixCls}--expand-row`}>
|
||||
<td
|
||||
class={`${this.prefixCls}--expand-content`}
|
||||
colspan={this.table.tableColumns.length}>
|
||||
{renderTemplateSlot.call(this, this.table, 'expand', { row, rowIndex })}
|
||||
</td>
|
||||
</tr>,
|
||||
])
|
||||
: <tr
|
||||
class={`${this.prefixCls}--empty-row`}>
|
||||
<td
|
||||
class={`${this.prefixCls}__body-cell ${this.prefixCls}--empty-content`}
|
||||
colspan={this.table.tableColumns.length}>
|
||||
{this.table.emptyText}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -1,84 +0,0 @@
|
||||
import { mixins } from './utils';
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default {
|
||||
name: 'TreeTable__footer',
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
render() {
|
||||
// 计算各列总和
|
||||
function renderCell({ key }, columnIndex) {
|
||||
if (columnIndex === 0) {
|
||||
return this.table.sumText;
|
||||
}
|
||||
const rows = this.table.bodyData;
|
||||
const values = rows.map(row => Number(row[key]));
|
||||
const precisions = [];
|
||||
let notNumber = true;
|
||||
values.forEach((value) => {
|
||||
if (!isNaN(value)) {
|
||||
notNumber = false;
|
||||
const decimal = value.toString().split('.')[1];
|
||||
precisions.push(decimal ? decimal.length : 0);
|
||||
}
|
||||
});
|
||||
const precision = Math.max.apply(null, precisions);
|
||||
if (!notNumber) {
|
||||
return values.reduce((prev, curr) => {
|
||||
const value = Number(curr);
|
||||
if (!isNaN(value)) {
|
||||
return parseFloat((prev + curr).toFixed(precision));
|
||||
}
|
||||
return prev;
|
||||
}, 0);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
// className
|
||||
function getClassName() {
|
||||
const classList = [];
|
||||
classList.push(`${this.prefixCls}__footer-cell`);
|
||||
if (this.table.border) {
|
||||
classList.push(`${this.prefixCls}--border-cell`);
|
||||
}
|
||||
return classList.join(' ');
|
||||
}
|
||||
|
||||
// Template
|
||||
return (
|
||||
<table cellspacing="0" cellpadding="0" border="0" class={ `${this.prefixCls}__footer` }>
|
||||
<colgroup>
|
||||
{ this.table.tableColumns.map(column =>
|
||||
<col width={ column.computedWidth || column.minWidth || column.width }></col>)
|
||||
}
|
||||
</colgroup>
|
||||
<tfoot>
|
||||
<tr class={ `${this.prefixCls}__footer-row` }>
|
||||
{ this.table.tableColumns.map((column, columnIndex) =>
|
||||
<td class={ getClassName.call(this) }>
|
||||
<div class={ `${this.prefixCls}__cell-inner` }>
|
||||
{ this.table.summaryMethod
|
||||
? this.table.summaryMethod(this.table.bodyData, column, columnIndex)
|
||||
: renderCell.call(this, column, columnIndex) }
|
||||
</div>
|
||||
</td>)
|
||||
}
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -1,108 +0,0 @@
|
||||
import Checkbox from "../Checkbox/Checkbox"; // eslint-disable-line
|
||||
import { mixins } from "./utils";
|
||||
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
export default {
|
||||
name: "TreeTable__header",
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
table() {
|
||||
return this.$parent;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleAllChecked(checked) {
|
||||
this.table.bodyData = this.table.bodyData.map(row => ({
|
||||
...row,
|
||||
_isChecked: checked
|
||||
}));
|
||||
}
|
||||
},
|
||||
render() {
|
||||
// className
|
||||
function getClassName(type, { headerAlign, key }) {
|
||||
const certainType = this.validateType(
|
||||
type,
|
||||
["cell", "inner"],
|
||||
"getClassName"
|
||||
);
|
||||
const classList = [];
|
||||
if (key == "_normalIndex") {
|
||||
classList.push(`${this.prefixCls}--center-cell`);
|
||||
}
|
||||
if (certainType.cell) {
|
||||
classList.push(`${this.prefixCls}__header-cell`);
|
||||
if (this.table.border) {
|
||||
classList.push(`${this.prefixCls}--border-cell`);
|
||||
}
|
||||
if (["center", "right"].indexOf(headerAlign) > -1) {
|
||||
classList.push(`${this.prefixCls}--${headerAlign}-cell`);
|
||||
}
|
||||
}
|
||||
if (certainType.inner) {
|
||||
classList.push(`${this.prefixCls}__cell-inner`);
|
||||
if (this.table.treeType && this.table.firstProp === key) {
|
||||
classList.push(`${this.prefixCls}--firstProp-header-inner`);
|
||||
}
|
||||
}
|
||||
return classList.join(" ");
|
||||
}
|
||||
|
||||
// 根据type渲染单元格Label
|
||||
function renderLabel(column, columnIndex) {
|
||||
if (
|
||||
this.isSelectionCell(this.table, columnIndex) &&
|
||||
this.selectType === "checkbox"
|
||||
) {
|
||||
const allCheck = this.table.bodyData.every(row => row._isChecked);
|
||||
const indeterminate =
|
||||
!allCheck && this.table.bodyData.some(row => row._isChecked);
|
||||
return (
|
||||
<Checkbox
|
||||
indeterminate={indeterminate}
|
||||
value={allCheck}
|
||||
onOn-change={checked => this.toggleAllChecked(checked)}
|
||||
></Checkbox>
|
||||
);
|
||||
}
|
||||
return column.title ? column.title : "";
|
||||
}
|
||||
|
||||
// Template
|
||||
return (
|
||||
<table
|
||||
cellspacing="0"
|
||||
cellpadding="0"
|
||||
border="0"
|
||||
class={`${this.prefixCls}__header`}
|
||||
>
|
||||
{/* <colgroup>
|
||||
{this.table.tableColumns.map(column => (
|
||||
<col
|
||||
width={column.computedWidth || column.minWidth || column.width}
|
||||
></col>
|
||||
))}
|
||||
</colgroup> */}
|
||||
<thead>
|
||||
<tr class={`${this.prefixCls}__header-row`}>
|
||||
{
|
||||
this.table.tableColumns.map((column, columnIndex) =>
|
||||
column.key ? (
|
||||
<th class={getClassName.call(this, "cell", column)}>
|
||||
<div class={getClassName.call(this, "inner", column)}>
|
||||
{renderLabel.call(this, column, columnIndex)}
|
||||
</div>
|
||||
</th>
|
||||
) : (
|
||||
""
|
||||
)
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
};
|
||||
Binary file not shown.
@@ -1,22 +0,0 @@
|
||||
// icon
|
||||
@font-face {font-family: "iconfont";
|
||||
src: url('iconfont.eot?t=1505310522875'); /* IE9*/
|
||||
src: url('iconfont.eot?t=1505310522875#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAW0AAsAAAAACOQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kggY21hcAAAAYAAAABuAAABojLtBtFnbHlmAAAB8AAAAa8AAAKA73SzT2hlYWQAAAOgAAAALwAAADYO3fRqaGhlYQAAA9AAAAAcAAAAJAfeA4ZobXR4AAAD7AAAABMAAAAUE+kAAGxvY2EAAAQAAAAADAAAAAwBbAHYbWF4cAAABAwAAAAeAAAAIAEUAF1uYW1lAAAELAAAAUUAAAJtPlT+fXBvc3QAAAV0AAAAQAAAAFryy5h0eJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/s04gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDwzZm7438AQw9zA0AAUZgTJAQAoHgyieJzFkcENwyAUQ98HyqHKKDmEZoEOklOnYOK/RmI+uXSCWDLG/pZAALyALK5iAfthDBxKLfLMO/LCJl+lRqL7fp7y3VuoKprV0KxO0qbyGOy5o/+xxPq9nV6YflNX9DY5fsA/k6Pj+yTpAn3jEO8AAHiclVDNitNQFD7n3slNE9vE5N7kpOn0J0mbKB3DGDMZRGw3bhQXA2LB5TyAbmfjohvBhQvfYEAEoc8wr+EDiK4KPkITU0EcXDmHw3fOgfN9fHygATTf+BUPQMIduA9P4AwAxRxjiw0xysqczdGLNI+UxbMki/QkzvljpFgov6jKlIQubLRwhA+iospyluFJuWCPsPCHiP1B+MKdHbr8I5pBNnpXP2Of0Bsnh/biXv30aKmKiexcdF2377ofOkLTOowd2Ba+Jt/QDFPUnzU79K7Gd9kYu/0sfP6qNxm45+/LN8MZGYjrNcrBxPqydEKn7behL92+frvXCcJeMlV48eNWILvD9Du0hXtgl+wSHIBZnJZLzNKyKgh9paPAdVca260hAxPBMBowz9t1uzUDuT8CswEDDtq8Gr7mADaM4QgetrKRhbozQooWeOrkKJVIojg9ccqqjcT3uBJ6lGNZnUYjnBU+ORbGaeYskM93m+kx4vGUrX5PQXK3kUSSrSS9JFWvFJHCjaIGJCFSugcOLeM6c7f6wyFZf/37+PO6AgD/x/vNnN/A7H8bhF86tmcbAHicY2BkYGAAYl/p/jnx/DZfGbhZGEDg6v0IKwT9/yELA7MEkMvBwAQSBQAZYgnZAHicY2BkYGBu+N/AEMPCAAJAkpEBFbACAEcLAm54nGNhYGBgfsnAwMKAwAAOmwD9AAAAAAAAdgCYAPYBQHicY2BkYGBgZQgEYhBgAmIuIGRg+A/mMwAAES0BcgAAeJxlj01OwzAQhV/6B6QSqqhgh+QFYgEo/RGrblhUavdddN+mTpsqiSPHrdQDcB6OwAk4AtyAO/BIJ5s2lsffvHljTwDc4Acejt8t95E9XDI7cg0XuBeuU38QbpBfhJto41W4Rf1N2MczpsJtdGF5g9e4YvaEd2EPHXwI13CNT+E69S/hBvlbuIk7/Aq30PHqwj7mXle4jUcv9sdWL5xeqeVBxaHJIpM5v4KZXu+Sha3S6pxrW8QmU4OgX0lTnWlb3VPs10PnIhVZk6oJqzpJjMqt2erQBRvn8lGvF4kehCblWGP+tsYCjnEFhSUOjDFCGGSIyujoO1Vm9K+xQ8Jee1Y9zed0WxTU/3OFAQL0z1xTurLSeTpPgT1fG1J1dCtuy56UNJFezUkSskJe1rZUQuoBNmVXjhF6XNGJPyhnSP8ACVpuyAAAAHicY2BigAAuBuyAlZGJkZmRhZGVkY2BsYI7MS89J1W3KDM9o4S3IKe0WLe4sDSxKFU3ny83Mw+Jy8AAAHSWD8A=') format('woff'),
|
||||
url('iconfont.ttf?t=1505310522875') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
|
||||
url('iconfont.svg?t=1505310522875#iconfont') format('svg'); /* iOS 4.1- */
|
||||
}
|
||||
|
||||
.zk-icon {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.zk-icon-plus-square-o:before { content: "\e631"; }
|
||||
|
||||
.zk-icon-minus-square-o:before { content: "\e632"; }
|
||||
|
||||
.zk-icon-angle-right:before { content: "\e633"; }
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<!--
|
||||
2013-9-30: Created.
|
||||
-->
|
||||
<svg>
|
||||
<metadata>
|
||||
Created by iconfont
|
||||
</metadata>
|
||||
<defs>
|
||||
|
||||
<font id="iconfont" horiz-adv-x="1024" >
|
||||
<font-face
|
||||
font-family="iconfont"
|
||||
font-weight="500"
|
||||
font-stretch="normal"
|
||||
units-per-em="1024"
|
||||
ascent="896"
|
||||
descent="-128"
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="x" unicode="x" horiz-adv-x="1001"
|
||||
d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
|
||||
t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
|
||||
t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
|
||||
|
||||
|
||||
|
||||
<glyph glyph-name="angle-right" unicode="" d="M384.087 97.474c-7.857 0-15.713 2.997-21.707 8.992-11.989 11.989-11.989 31.426 0 43.415l234.118 234.12-234.118 234.118c-11.988 11.989-11.988 31.427 0 43.416 11.989 11.988 31.426 11.988 43.416 0l255.826-255.827c11.989-11.989 11.989-31.427 0-43.416l-255.826-255.827c-5.995-5.995-13.851-8.992-21.708-8.992z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="plus-square-o" unicode="" d="M810.666667 768H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333v-597.333334c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333V682.666667c0 46.933333-38.4 85.333333-85.333333 85.333333z m42.666666-682.666667c0-25.6-17.066667-42.666667-42.666666-42.666666H213.333333c-25.6 0-42.666667 17.066667-42.666666 42.666666V682.666667c0 25.6 17.066667 42.666667 42.666666 42.666666h597.333334c25.6 0 42.666667-17.066667 42.666666-42.666666v-597.333334zM768 384c0-25.6-17.066667-42.666667-42.666667-42.666667H298.666667c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h426.666666c25.6 0 42.666667-17.066667 42.666667-42.666667zM512 640c25.6 0 42.666667-17.066667 42.666667-42.666667v-426.666666c0-25.6-17.066667-42.666667-42.666667-42.666667s-42.666667 17.066667-42.666667 42.666667V597.333333c0 25.6 17.066667 42.666667 42.666667 42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="minus-square-o" unicode="" d="M810.666667 768H213.333333c-46.933333 0-85.333333-38.4-85.333333-85.333333v-597.333334c0-46.933333 38.4-85.333333 85.333333-85.333333h597.333334c46.933333 0 85.333333 38.4 85.333333 85.333333V682.666667c0 46.933333-38.4 85.333333-85.333333 85.333333z m42.666666-682.666667c0-25.6-17.066667-42.666667-42.666666-42.666666H213.333333c-25.6 0-42.666667 17.066667-42.666666 42.666666V682.666667c0 25.6 17.066667 42.666667 42.666666 42.666666h597.333334c25.6 0 42.666667-17.066667 42.666666-42.666666v-597.333334zM768 384c0-25.6-17.066667-42.666667-42.666667-42.666667H298.666667c-25.6 0-42.666667 17.066667-42.666667 42.666667s17.066667 42.666667 42.666667 42.666667h426.666666c25.6 0 42.666667-17.066667 42.666667-42.666667z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
|
||||
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
Before Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
Binary file not shown.
@@ -1,6 +0,0 @@
|
||||
import mixins from './mixins';
|
||||
import scrollBarWidth from './scrollBarWidth';
|
||||
export {
|
||||
mixins,
|
||||
scrollBarWidth
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
prefixCls: 'zk-table',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
validateType(type, validTypes, funcName, isReturn = true) {
|
||||
if (validTypes.indexOf(type) < 0) throw new Error(`${funcName}'s type must is ${validTypes.join(' or ')}.`);
|
||||
if (isReturn) {
|
||||
const certainType = {};
|
||||
validTypes.forEach((item) => {
|
||||
certainType[item] = item === type;
|
||||
});
|
||||
return certainType;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
isExpandCell(table, columnIndex) {
|
||||
return table.expandType && (
|
||||
(table.showIndex && columnIndex === 1) ||
|
||||
(!table.showIndex && columnIndex === 0)
|
||||
);
|
||||
},
|
||||
isSelectionCell(table, columnIndex) {
|
||||
return table.selectable && (
|
||||
(table.showIndex && table.expandType && columnIndex === 2) ||
|
||||
(!table.showIndex && table.expandType && columnIndex === 1) ||
|
||||
(table.showIndex && !table.expandType && columnIndex === 1) ||
|
||||
(!table.showIndex && !table.expandType && columnIndex === 0)
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,26 +0,0 @@
|
||||
let scrollBarWidth;
|
||||
|
||||
export default function getScrollBarWidth() {
|
||||
if (typeof document === "undefined") return 0;
|
||||
if (scrollBarWidth !== undefined) return scrollBarWidth;
|
||||
|
||||
const outer = document.createElement("div");
|
||||
outer.style.visibility = "hidden";
|
||||
outer.style.width = "100px";
|
||||
outer.style.position = "absolute";
|
||||
outer.style.top = "-9999px";
|
||||
document.body.appendChild(outer);
|
||||
|
||||
const widthNoScroll = outer.offsetWidth;
|
||||
outer.style.overflow = "scroll";
|
||||
|
||||
const inner = document.createElement("div");
|
||||
inner.style.width = "100%";
|
||||
outer.appendChild(inner);
|
||||
|
||||
const widthWithScroll = inner.offsetWidth;
|
||||
outer.parentNode.removeChild(outer);
|
||||
scrollBarWidth = widthNoScroll - widthWithScroll;
|
||||
|
||||
return scrollBarWidth;
|
||||
}
|
||||
@@ -24,6 +24,7 @@ function refreshAccessToken(token) {
|
||||
return service({
|
||||
method: "get",
|
||||
url: `/passport/user/refresh/${token}`,
|
||||
_isRefreshRequest: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -40,8 +41,6 @@ function redirectToLogin(message) {
|
||||
router.push("/login");
|
||||
}
|
||||
}
|
||||
var isRefreshToken = 0;
|
||||
const refreshToken = getTokenDebounce();
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
if (config.method == "get") {
|
||||
@@ -69,113 +68,86 @@ service.interceptors.response.use(
|
||||
response => {
|
||||
const data = response.data;
|
||||
// 根据返回的code值来做不同的处理(和后端约定)
|
||||
if (!data.success && data.message) {
|
||||
Message.error(data.message);
|
||||
}
|
||||
switch (data.code) {
|
||||
case 400:
|
||||
if (data.message !== null) {
|
||||
Message.error(data.message);
|
||||
} else {
|
||||
Message.error("系统异常");
|
||||
}
|
||||
break;
|
||||
case 20004:
|
||||
case 401:
|
||||
redirectToLogin(data.message !== null ? data.message : null);
|
||||
case 20004:
|
||||
redirectToLogin(data.message || null);
|
||||
return data;
|
||||
break;
|
||||
case 400:
|
||||
case 500:
|
||||
// 系统异常
|
||||
if (data.message !== null) {
|
||||
Message.error(data.message);
|
||||
} else {
|
||||
Message.error("系统异常");
|
||||
}
|
||||
break;
|
||||
Message.error(data.message || "系统异常");
|
||||
return data;
|
||||
default:
|
||||
if (!data.success && data.message) {
|
||||
Message.error(data.message);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
},
|
||||
async error => {
|
||||
// 返回状态码不为200时候的错误处理
|
||||
if (error.response) {
|
||||
if (error.response.status === 401) {
|
||||
const response = error.response;
|
||||
const config = error.config;
|
||||
if (response) {
|
||||
const code = response.data && response.data.code;
|
||||
if (response.status === 401) {
|
||||
// 这种情况一般调到登录页
|
||||
} else if (error.response.status === 404) {
|
||||
// 避免刷新token报错
|
||||
} else if (error.response.status === 403 || error.response.data.code === 20004) {
|
||||
isRefreshToken++;
|
||||
if (isRefreshToken === 1) {
|
||||
const getTokenRes = await refreshToken();
|
||||
if (getTokenRes === "success") {
|
||||
// 刷新token
|
||||
if (isRefreshToken === 1) {
|
||||
error.response.config.headers.accessToken = getStore(
|
||||
"accessToken"
|
||||
);
|
||||
return service(error.response.config);
|
||||
} else {
|
||||
const router = getRouter();
|
||||
if (router) router.go(0);
|
||||
}
|
||||
} else {
|
||||
redirectToLogin(null);
|
||||
}
|
||||
isRefreshToken = 0;
|
||||
redirectToLogin("登录状态已过期,请重新登录");
|
||||
} else if (
|
||||
(response.status === 403 || code === 20004) &&
|
||||
config &&
|
||||
!config._isRefreshRequest &&
|
||||
!config._retryAfterRefresh
|
||||
) {
|
||||
// accessToken 过期:刷新 token 后重试原请求
|
||||
config._retryAfterRefresh = true;
|
||||
const result = await refreshToken();
|
||||
if (result === "success") {
|
||||
config.headers.accessToken = getStore("accessToken");
|
||||
return service(config);
|
||||
}
|
||||
redirectToLogin(null);
|
||||
} else if (response.status === 404) {
|
||||
// 避免刷新token报错
|
||||
Message.error("请求的资源不存在");
|
||||
} else {
|
||||
// 其他错误处理
|
||||
Message.error(error.response.data.message);
|
||||
Message.error(
|
||||
(response.data && response.data.message) || "系统异常,请稍后重试"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 断网/超时等无响应的错误
|
||||
Message.error(
|
||||
error.code === "ECONNABORTED"
|
||||
? "请求超时,请稍后重试"
|
||||
: "网络异常,请检查网络连接"
|
||||
);
|
||||
}
|
||||
/* router.push("/login") */
|
||||
return Promise.resolve(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 防抖闭包来一波
|
||||
function getTokenDebounce() {
|
||||
let lock = false;
|
||||
let success = false;
|
||||
return function() {
|
||||
if (!lock) {
|
||||
lock = true;
|
||||
let oldRefreshToken = getStore("refreshToken");
|
||||
refreshAccessToken(oldRefreshToken)
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
let { accessToken, refreshToken } = res.result;
|
||||
setStore("accessToken", accessToken);
|
||||
setStore("refreshToken", refreshToken);
|
||||
|
||||
success = true;
|
||||
lock = false;
|
||||
} else {
|
||||
success = false;
|
||||
lock = false;
|
||||
redirectToLogin(null);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
success = false;
|
||||
lock = false;
|
||||
});
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
// 一直看lock,直到请求失败或者成功
|
||||
const timer = setInterval(() => {
|
||||
if (!lock) {
|
||||
clearInterval(timer);
|
||||
if (success) {
|
||||
resolve("success");
|
||||
} else {
|
||||
resolve("fail");
|
||||
}
|
||||
// 刷新 token 单例 Promise:并发 403 时共享同一次刷新,避免重复请求
|
||||
let refreshTokenPromise = null;
|
||||
function refreshToken() {
|
||||
if (!refreshTokenPromise) {
|
||||
const oldRefreshToken = getStore("refreshToken");
|
||||
refreshTokenPromise = refreshAccessToken(oldRefreshToken)
|
||||
.then(res => {
|
||||
if (res.success) {
|
||||
const { accessToken, refreshToken: newRefreshToken } = res.result;
|
||||
setStore("accessToken", accessToken);
|
||||
setStore("refreshToken", newRefreshToken);
|
||||
return "success";
|
||||
}
|
||||
}, 500); // 轮询时间间隔
|
||||
});
|
||||
};
|
||||
return "fail";
|
||||
})
|
||||
.catch(() => "fail")
|
||||
.finally(() => {
|
||||
refreshTokenPromise = null;
|
||||
});
|
||||
}
|
||||
return refreshTokenPromise;
|
||||
}
|
||||
|
||||
export const getRequest = (url, params, resBlob) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createApp } from "vue";
|
||||
import "core-js/stable";
|
||||
import "./styles/theme.less";
|
||||
import "@/styles/common.scss";
|
||||
import App from "./App.vue";
|
||||
import { router } from "./router/index";
|
||||
import store from "./store";
|
||||
@@ -85,5 +86,12 @@ router.isReady().then(() => {
|
||||
app.mount("#app");
|
||||
});
|
||||
|
||||
// axios 错误已在拦截器统一 toast 提示,页面未写 .catch 时不再触发未捕获 rejection 浮层
|
||||
window.addEventListener("unhandledrejection", (event) => {
|
||||
if (event.reason && event.reason.isAxiosError) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// 登录后由 App.vue 触发 initRouter 拉取/更新菜单
|
||||
export { app, util };
|
||||
|
||||
@@ -96,15 +96,11 @@ ul,li{
|
||||
white-space: nowrap;
|
||||
}
|
||||
// 主题颜色
|
||||
@import "./variables.scss";
|
||||
|
||||
$success_color: #68cabe;
|
||||
$warning_color: #fa6419;
|
||||
$error_color: #ff3c2a;
|
||||
$theme_color: #FF5C58;
|
||||
.theme_color {
|
||||
color: $theme_color !important;
|
||||
}
|
||||
$bg_color: #f1f6fa;
|
||||
|
||||
.wes {
|
||||
/* 多出部分用省略号表示 , 用于一行 */
|
||||
|
||||
6
manager/src/styles/variables.scss
Normal file
6
manager/src/styles/variables.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
// 仅放变量:通过 style-resources-loader 注入到每个组件样式块,不会产生重复 CSS
|
||||
$success_color: #68cabe;
|
||||
$warning_color: #fa6419;
|
||||
$error_color: #ff3c2a;
|
||||
$theme_color: #FF5C58;
|
||||
$bg_color: #f1f6fa;
|
||||
@@ -4,7 +4,6 @@
|
||||
export function printElement(elementId, title = "打印") {
|
||||
const el = document.getElementById(elementId);
|
||||
if (!el) {
|
||||
console.warn(`[print] element #${elementId} not found`);
|
||||
return;
|
||||
}
|
||||
const iframe = document.createElement("iframe");
|
||||
|
||||
@@ -142,8 +142,7 @@ export default {
|
||||
value: String(item.sortOrder),
|
||||
label: item.gradeName || `等级值${item.sortOrder}`,
|
||||
}));
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
},
|
||||
formatGrade(name, gradeId) {
|
||||
if (name) {
|
||||
|
||||
@@ -60,7 +60,6 @@ export function useChat(liveId, userInfo, liveDetail) {
|
||||
}
|
||||
if (!groupID.value) {
|
||||
initError.value = "直播间群组 ID 不存在";
|
||||
console.warn("groupID 不存在,跳过 IM 初始化");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -160,18 +159,15 @@ export function useChat(liveId, userInfo, liveDetail) {
|
||||
}
|
||||
|
||||
function onSdkNotReady() {
|
||||
console.log("[SDK Not Ready]");
|
||||
imReady.value = false;
|
||||
}
|
||||
|
||||
function onSdkReady() {
|
||||
console.log("[SDK Ready]");
|
||||
imReady.value = true;
|
||||
updateUserInfo();
|
||||
}
|
||||
|
||||
function onKickedOut() {
|
||||
console.log("[用户被踢下线]");
|
||||
imReady.value = false;
|
||||
initError.value = "IM 已下线,请刷新页面";
|
||||
}
|
||||
@@ -203,11 +199,10 @@ export function useChat(liveId, userInfo, liveDetail) {
|
||||
}
|
||||
|
||||
try {
|
||||
const imResponse = await chat.value.joinGroup({
|
||||
await chat.value.joinGroup({
|
||||
groupID: groupID.value,
|
||||
type: TencentCloudChat.TYPES.GRP_AVCHATROOM,
|
||||
});
|
||||
console.log("[加群成功]", imResponse);
|
||||
} catch (imError) {
|
||||
console.warn("joinGroup error:", imError);
|
||||
throw imError;
|
||||
|
||||
@@ -21,7 +21,6 @@ export async function fetchLiveSetting(force = false) {
|
||||
cachedSetting = res.result;
|
||||
return cachedSetting;
|
||||
}
|
||||
console.warn("获取直播配置失败", res);
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.error("获取直播配置异常:", error);
|
||||
|
||||
@@ -327,8 +327,7 @@ export default {
|
||||
if (res.success && res.result?.buyerDomain) {
|
||||
this.wapUrl = res.result.buyerDomain;
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -759,9 +759,7 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(this.typeList)
|
||||
if (this.typeList.length >= 3) {
|
||||
console.log(123123)
|
||||
this.getContentPrice()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -232,9 +232,7 @@ export default {
|
||||
handleAddNav() {
|
||||
this.navList.list.push({ name: "", url: "", title: "" });
|
||||
},
|
||||
handleMoveEnd({ newIndex, oldIndex }) {
|
||||
console.log("index", newIndex, oldIndex);
|
||||
},
|
||||
handleMoveEnd({ newIndex, oldIndex }) {},
|
||||
handleModel(type) {
|
||||
if (type == "topAdvert") {
|
||||
this.draftTopAdvert = JSON.parse(JSON.stringify(this.topAdvert));
|
||||
|
||||
@@ -285,7 +285,6 @@ export default {
|
||||
},
|
||||
// 选择商品回调
|
||||
selectedGoodsData(val) {
|
||||
console.log(val);
|
||||
let goods = val[0];
|
||||
this.selected.img = goods.thumbnail;
|
||||
this.selected.price = goods.price;
|
||||
|
||||
@@ -160,9 +160,7 @@ export default {
|
||||
watch: {
|
||||
modelForm: {
|
||||
deep: true,
|
||||
handler: function (val) {
|
||||
console.log(val);
|
||||
},
|
||||
handler: function (val) {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -116,10 +116,6 @@ export default {
|
||||
advertising: {
|
||||
handler(val) {
|
||||
this.$store.state.openStyleStore = val;
|
||||
console.log(
|
||||
"this.$store.state.openStyleStore",
|
||||
this.$store.state.openStyleStore
|
||||
);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
|
||||
@@ -119,10 +119,6 @@ export default {
|
||||
advertising: {
|
||||
handler(val) {
|
||||
this.$store.state.openStyleStore = val;
|
||||
console.log(
|
||||
"this.$store.state.openStyleStore",
|
||||
this.$store.state.openStyleStore
|
||||
);
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
import * as API_Other from "@/api/other";
|
||||
|
||||
// 获取楼层装修信息
|
||||
export function initData(id) {
|
||||
API_Other.getHomeData(id).then(res => {
|
||||
debugger
|
||||
homeData = res;
|
||||
console.log(res)
|
||||
});
|
||||
}
|
||||
|
||||
export let homeData = {};
|
||||
|
||||
/**
|
||||
* drawer:true 广告右侧打开抽屉中显示
|
||||
* drawerPromotions:true 广告右侧打开抽屉中显示
|
||||
|
||||
@@ -621,8 +621,6 @@ export default {
|
||||
return item.___index != this.goodsSelectedIndex;
|
||||
});
|
||||
this.res.options.list[0].titleWay[this.goodsSelectedIndex] = data;
|
||||
|
||||
console.log(this.res.options.list[0]);
|
||||
},
|
||||
// 商品排序
|
||||
slotGoods(list, key, val) {
|
||||
@@ -659,7 +657,6 @@ export default {
|
||||
|
||||
// 轮播图排序
|
||||
slotBanner(val, key, index, down) {
|
||||
console.log(val);
|
||||
if (down == "down") {
|
||||
this.downData(val.options.list, index);
|
||||
} else {
|
||||
|
||||
@@ -192,15 +192,12 @@ export default {
|
||||
this.saveDialog = false;
|
||||
this.$Message.error("修改失败,请稍后重试");
|
||||
}
|
||||
console.log(res);
|
||||
})
|
||||
.catch(error => {});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// 更新
|
||||
update(submitWay) {
|
||||
console.log(this.$store.state.openStyleStore[0], "123123123");
|
||||
if (this.$store.state.openStyleStore == void 0) {
|
||||
this.$Message.error("请装修楼层!");
|
||||
return false;
|
||||
@@ -209,7 +206,6 @@ export default {
|
||||
|
||||
let id = this.$route.query.id;
|
||||
const pagetype = this.$route.query.pagetype;
|
||||
console.log(this.$store.state.openStyleStore, submitWay);
|
||||
const pageType = {
|
||||
INDEX: "INDEX",
|
||||
ALERT: "OPEN_SCREEN_PAGE",
|
||||
@@ -239,9 +235,7 @@ export default {
|
||||
this.saveDialog = false;
|
||||
this.$Message.error("修改失败,请稍后重试");
|
||||
}
|
||||
console.log(res);
|
||||
})
|
||||
.catch((error) => {});
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -270,9 +264,7 @@ export default {
|
||||
this.saveDialog = false;
|
||||
this.$Message.error("保存失败,请稍后重试");
|
||||
}
|
||||
console.log(res);
|
||||
})
|
||||
.catch(error => {});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
>
|
||||
<el-table-column prop="articleCategoryName" label="分类名称" min-width="200" />
|
||||
<el-table-column prop="sort" label="排序" width="120" />
|
||||
<el-table-column label="操作" width="320" align="center">
|
||||
<el-table-column label="操作" width="320" align="right">
|
||||
<template #default="{ row }">
|
||||
<template v-if="row">
|
||||
<a class="link-text" @click="edit(row)">编辑</a>
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
title="这里展示历史某一天的热词数据统计,可根据需求配置每日持久化多少条数据。"
|
||||
/>
|
||||
|
||||
<div id="container"></div>
|
||||
<div v-show="hasData" id="container"></div>
|
||||
<el-empty v-if="!hasData" description="该日期暂无热词数据" :image-size="100" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Chart } from "@antv/g2";
|
||||
import { getHotWordsHistory } from "@/api/index";
|
||||
import { Message } from "@/utils/message";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
@@ -34,6 +34,7 @@ export default {
|
||||
},
|
||||
hotWordsChart: null,
|
||||
hotWordsData: [],
|
||||
hasData: true,
|
||||
endMonth: null,
|
||||
};
|
||||
},
|
||||
@@ -60,13 +61,11 @@ export default {
|
||||
const res = await getHotWordsHistory(this.params);
|
||||
if (res.success) {
|
||||
this.hotWordsData = res.result || [];
|
||||
if (this.hotWordsChart) {
|
||||
this.hasData = this.hotWordsData.length > 0;
|
||||
if (this.hasData && this.hotWordsChart) {
|
||||
this.hotWordsChart.changeData(this.hotWordsData);
|
||||
this.hotWordsChart.render();
|
||||
}
|
||||
if (!this.hotWordsData.length) {
|
||||
Message.error("暂无数据");
|
||||
}
|
||||
}
|
||||
},
|
||||
init() {
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
</div>
|
||||
</el-affix>
|
||||
|
||||
<div id="container"></div>
|
||||
<el-table border :data="hotWordsData" style="width: 100%">
|
||||
<div v-show="hasData" id="container"></div>
|
||||
<el-table v-if="hasData" border :data="hotWordsData" style="width: 100%">
|
||||
<el-table-column prop="keywords" label="热词名称" min-width="160" />
|
||||
<el-table-column prop="score" label="搜索次数" min-width="120" />
|
||||
</el-table>
|
||||
<el-empty v-else description="暂无热词统计数据" :image-size="100" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -40,6 +41,7 @@ export default {
|
||||
},
|
||||
hotWordsChart: "",
|
||||
hotWordsData: [],
|
||||
hasData: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -61,7 +63,11 @@ export default {
|
||||
async search() {
|
||||
const res = await getHotWordsStatistics(this.params);
|
||||
if (res.success) {
|
||||
this.hotWordsData = res.result;
|
||||
this.hotWordsData = res.result || [];
|
||||
this.hasData = this.hotWordsData.length > 0;
|
||||
if (!this.hasData) {
|
||||
return;
|
||||
}
|
||||
if (!this.hotWordsChart) {
|
||||
this.hotWordsChart = new Chart({
|
||||
container: "container",
|
||||
|
||||
@@ -10,13 +10,19 @@
|
||||
title="这里展示今日系统中搜索前一百的搜索热词,分数为热词在排序系统中的分数,分数越高,可以在用户获取热词时进行优先展示(首页商品搜索栏下方推荐位)(分数可以填写负数,会降低推荐度)"
|
||||
/>
|
||||
|
||||
<div class="card-list">
|
||||
<el-card v-for="words in data" :key="words" class="card-item" shadow="hover">
|
||||
<div class="card-item-inner">
|
||||
<a href="#" class="word-link" @click.prevent="add(words)">{{ words }}</a>
|
||||
<el-icon class="close-icon" @click="deleteWords(words)"><Close /></el-icon>
|
||||
</div>
|
||||
</el-card>
|
||||
<div class="word-list">
|
||||
<el-tag
|
||||
v-for="words in data"
|
||||
:key="words"
|
||||
size="large"
|
||||
closable
|
||||
class="word-tag"
|
||||
@close="deleteWords(words)"
|
||||
@click="add(words)"
|
||||
>
|
||||
{{ words }}
|
||||
</el-tag>
|
||||
<el-empty v-if="!data.length" description="暂无热词,点击上方按钮设置" :image-size="80" />
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
@@ -44,13 +50,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Close } from "@element-plus/icons-vue";
|
||||
import { getHotWords, setHotWords, deleteHotWords } from "@/api/index";
|
||||
import { regular } from "@/utils";
|
||||
|
||||
export default {
|
||||
name: "todayHotWords",
|
||||
components: { Close },
|
||||
data() {
|
||||
return {
|
||||
submitLoading: false,
|
||||
@@ -127,36 +131,23 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-list {
|
||||
.word-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
min-width: 100px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.card-item-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.word-link {
|
||||
color: var(--el-color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
.word-tag {
|
||||
cursor: pointer;
|
||||
color: var(--el-text-color-secondary);
|
||||
padding: 0 14px;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
color: var(--el-color-danger);
|
||||
color: var(--el-color-primary);
|
||||
border-color: var(--el-color-primary);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -461,7 +461,6 @@ export default {
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
|
||||
@@ -286,6 +286,8 @@ export default {
|
||||
storeId: e.storeId,
|
||||
storeName: e.storeName,
|
||||
skuId: e.id,
|
||||
goodsId: e.goodsId,
|
||||
thumbnail: e.thumbnail || "",
|
||||
goodsType: e.goodsType,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -60,29 +60,19 @@
|
||||
style="width: 100%"
|
||||
@sort-change="changeSort"
|
||||
>
|
||||
<el-table-column prop="goodsId" label="商品编号" width="180" show-overflow-tooltip />
|
||||
<el-table-column label="商品图片" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<img
|
||||
v-if="row && row.thumbnail"
|
||||
:src="row.thumbnail"
|
||||
style="height: 50px; width: 50px; object-fit: cover"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品名称" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<template v-if="row">
|
||||
<a class="link-text mr_10" @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
|
||||
<el-popover trigger="hover" title="扫码在手机中查看" placement="top" width="180">
|
||||
<template #reference>
|
||||
<img
|
||||
src="../../../assets/qrcode.svg"
|
||||
class="hover-pointer"
|
||||
width="20"
|
||||
height="20"
|
||||
alt="qrcode"
|
||||
/>
|
||||
</template>
|
||||
<vue-qr
|
||||
:text="wapLinkTo(row.goodsId, row.skuId)"
|
||||
:margin="0"
|
||||
color-dark="#000"
|
||||
color-light="#fff"
|
||||
:size="150"
|
||||
/>
|
||||
</el-popover>
|
||||
</template>
|
||||
<a v-if="row" class="link-text" @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="库存数量" width="100">
|
||||
@@ -156,11 +146,9 @@
|
||||
|
||||
<script>
|
||||
import { getKanJiaGoodsList, delKanJiaGoods } from "@/api/promotion";
|
||||
import vueQr from "vue-qr";
|
||||
|
||||
export default {
|
||||
name: "kanjia-activity-goods",
|
||||
components: { vueQr },
|
||||
data() {
|
||||
return {
|
||||
selectDate: [],
|
||||
@@ -290,13 +278,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mr_10 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.hover-pointer {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.padding-row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -69,29 +69,19 @@
|
||||
class="mt_10"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column label="商品名称" min-width="200" fixed="left" show-overflow-tooltip>
|
||||
<el-table-column prop="goodsId" label="商品编号" width="180" show-overflow-tooltip />
|
||||
<el-table-column label="商品图片" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<template v-if="row">
|
||||
<a class="link-text mr_10" @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
|
||||
<el-popover trigger="hover" title="扫码在手机中查看" placement="top" width="180">
|
||||
<template #reference>
|
||||
<img
|
||||
src="../../../assets/qrcode.svg"
|
||||
class="hover-pointer"
|
||||
width="20"
|
||||
height="20"
|
||||
alt="qrcode"
|
||||
/>
|
||||
</template>
|
||||
<vue-qr
|
||||
:text="wapLinkTo(row.goodsId, row.skuId)"
|
||||
:margin="0"
|
||||
color-dark="#000"
|
||||
color-light="#fff"
|
||||
:size="150"
|
||||
/>
|
||||
</el-popover>
|
||||
</template>
|
||||
<img
|
||||
v-if="row && row.thumbnail"
|
||||
:src="row.thumbnail"
|
||||
style="height: 50px; width: 50px; object-fit: cover"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="商品名称" min-width="200" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<a v-if="row" class="link-text" @click="linkTo(row.goodsId, row.skuId)">{{ row.goodsName }}</a>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="市场价" width="110">
|
||||
@@ -171,11 +161,9 @@ import {
|
||||
editPointsGoodsStatus,
|
||||
deletePointsGoodsStatus,
|
||||
} from "@/api/promotion";
|
||||
import vueQr from "vue-qr";
|
||||
|
||||
export default {
|
||||
name: "pointsGoods",
|
||||
components: { vueQr },
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
@@ -307,13 +295,6 @@ export default {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.mr_10 {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.hover-pointer {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.op-split {
|
||||
margin: 0 8px;
|
||||
color: #dcdee2;
|
||||
|
||||
@@ -43,38 +43,38 @@
|
||||
<div>
|
||||
<h3 class="ml_10">结算详细</h3>
|
||||
<el-table :data="billData" border style="width: 100%">
|
||||
<el-table-column label="结算金额" prop="billPrice" align="center" width="200" fixed="left">
|
||||
<el-table-column label="结算金额" prop="billPrice" align="center" width="160" fixed="left">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.billPrice) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收入" align="center">
|
||||
<el-table-column label="用户实付" prop="orderPrice" align="center" width="200">
|
||||
<el-table-column label="用户实付" prop="orderPrice" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.orderPrice) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平台优惠券补贴" prop="siteCouponCommission" align="center" width="200">
|
||||
<el-table-column label="平台优惠券补贴" prop="siteCouponCommission" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.siteCouponCommission) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="积分商品补贴" prop="pointSettlementPrice" align="center" width="200">
|
||||
<el-table-column label="积分商品补贴" prop="pointSettlementPrice" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.pointSettlementPrice) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="砍价商品补贴" prop="kanjiaSettlementPrice" align="center" width="200">
|
||||
<el-table-column label="砍价商品补贴" prop="kanjiaSettlementPrice" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.kanjiaSettlementPrice) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="礼品卡补贴" prop="giftCardSubsidy" align="center" width="200">
|
||||
<el-table-column label="礼品卡补贴" prop="giftCardSubsidy" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.giftCardSubsidy) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="分销佣金" prop="distributionCommission" align="center" width="200">
|
||||
<el-table-column label="分销佣金" prop="distributionCommission" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<priceColorScheme
|
||||
v-if="row"
|
||||
@@ -83,7 +83,7 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="平台服务费" prop="commissionPrice" align="center" width="200">
|
||||
<el-table-column label="平台服务费" prop="commissionPrice" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<priceColorScheme
|
||||
v-if="row"
|
||||
@@ -94,7 +94,7 @@
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
<el-table-column label="退款" align="center">
|
||||
<el-table-column label="退款金额" prop="refundPrice" align="center" width="200">
|
||||
<el-table-column label="退款金额" prop="refundPrice" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<priceColorScheme v-if="row" :value="negate(row.refundPrice)" :color="$mainColor" />
|
||||
</template>
|
||||
@@ -103,7 +103,7 @@
|
||||
label="退单返还平台优惠券补贴"
|
||||
prop="siteCouponRefundCommission"
|
||||
align="center"
|
||||
width="200"
|
||||
width="160"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<priceColorScheme
|
||||
@@ -117,7 +117,7 @@
|
||||
label="退单返还积分商品补贴"
|
||||
prop="pointRefundSettlementPrice"
|
||||
align="center"
|
||||
width="200"
|
||||
width="160"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<priceColorScheme
|
||||
@@ -131,7 +131,7 @@
|
||||
label="退单返还砍价商品补贴"
|
||||
prop="kanjiaRefundSettlementPrice"
|
||||
align="center"
|
||||
width="200"
|
||||
width="160"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<priceColorScheme
|
||||
@@ -141,7 +141,7 @@
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="礼品卡返还" prop="giftCardRefundSubsidy" align="center" width="200">
|
||||
<el-table-column label="礼品卡返还" prop="giftCardRefundSubsidy" align="center" width="160">
|
||||
<template #default="{ row }">
|
||||
<priceColorScheme
|
||||
v-if="row"
|
||||
@@ -154,7 +154,7 @@
|
||||
label="退单返还分销佣金"
|
||||
prop="distributionRefundCommission"
|
||||
align="center"
|
||||
width="200"
|
||||
width="160"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.distributionRefundCommission) }}</span>
|
||||
@@ -164,7 +164,7 @@
|
||||
label="退单返还平台服务费"
|
||||
prop="refundCommissionPrice"
|
||||
align="center"
|
||||
width="200"
|
||||
width="160"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row">{{ formatPrice(row.refundCommissionPrice) }}</span>
|
||||
@@ -450,9 +450,6 @@ export default {
|
||||
} else {
|
||||
navigator.msSaveBlob(blob, "结算单-" + this.id + ".xlsx");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
},
|
||||
init() {
|
||||
@@ -556,12 +553,16 @@ table {
|
||||
margin-left: 40px;
|
||||
|
||||
tr {
|
||||
font-size: 12px;
|
||||
height: 40px;
|
||||
padding: 10px;
|
||||
|
||||
td:nth-child(1) {
|
||||
width: 120px;
|
||||
width: 140px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
td:nth-child(2) {
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,56 @@
|
||||
<template>
|
||||
<div class="search">
|
||||
<el-card>
|
||||
<el-form
|
||||
ref="searchForm"
|
||||
:model="searchForm"
|
||||
inline
|
||||
label-width="70px"
|
||||
class="search-form"
|
||||
@keyup.enter="handleSearch"
|
||||
>
|
||||
<el-form-item label="账单号">
|
||||
<el-input
|
||||
v-model="searchForm.sn"
|
||||
placeholder="请输入账单号"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺名称">
|
||||
<el-input
|
||||
v-model="searchForm.storeName"
|
||||
placeholder="请输入店铺名称"
|
||||
clearable
|
||||
style="width: 240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="生成时间">
|
||||
<el-date-picker
|
||||
v-model="selectDate"
|
||||
type="daterange"
|
||||
clearable
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
:default-time="defaultTime"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
style="width: 260px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" class="search-btn" @click="handleSearch">搜索</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<el-card>
|
||||
<el-tabs v-model="activeStatus" @tab-change="handleStatusChange">
|
||||
<el-tab-pane label="全部" name="" />
|
||||
<el-tab-pane label="已出账" name="OUT" />
|
||||
<el-tab-pane label="已对账" name="CHECK" />
|
||||
<el-tab-pane label="已付款" name="COMPLETE" />
|
||||
</el-tabs>
|
||||
<div class="mb_10">
|
||||
<el-button type="primary" @click="handleExportList">导出列表</el-button>
|
||||
<el-button :disabled="selectCount === 0" @click="handleBatchDownload">批量下载</el-button>
|
||||
@@ -66,11 +116,19 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
selectDate: [],
|
||||
defaultTime: [new Date(2000, 0, 1, 0, 0, 0), new Date(2000, 0, 1, 23, 59, 59)],
|
||||
activeStatus: "",
|
||||
searchForm: {
|
||||
pageNumber: 1,
|
||||
pageSize: 20,
|
||||
sort: "createTime",
|
||||
order: "desc",
|
||||
sn: "",
|
||||
storeName: "",
|
||||
billStatus: "",
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
},
|
||||
selectList: [],
|
||||
selectCount: 0,
|
||||
@@ -102,14 +160,32 @@ export default {
|
||||
this.selectList = e;
|
||||
this.selectCount = e.length;
|
||||
},
|
||||
handleStatusChange(name) {
|
||||
this.searchForm.billStatus = name;
|
||||
this.searchForm.pageNumber = 1;
|
||||
this.getDataList();
|
||||
},
|
||||
handleSearch() {
|
||||
this.searchForm.pageNumber = 1;
|
||||
if (this.selectDate && this.selectDate[0] && this.selectDate[1]) {
|
||||
this.searchForm.startDate = this.selectDate[0];
|
||||
this.searchForm.endDate = this.selectDate[1];
|
||||
} else {
|
||||
this.searchForm.startDate = null;
|
||||
this.searchForm.endDate = null;
|
||||
}
|
||||
this.getDataList();
|
||||
},
|
||||
handleReset() {
|
||||
this.selectDate = [];
|
||||
this.searchForm.sn = "";
|
||||
this.searchForm.storeName = "";
|
||||
this.searchForm.startDate = null;
|
||||
this.searchForm.endDate = null;
|
||||
this.handleSearch();
|
||||
},
|
||||
getDataList() {
|
||||
this.loading = true;
|
||||
if (this.searchForm.startTime) {
|
||||
this.searchForm.startTime = this.$filters.unixToDate(this.searchForm.startTime / 1000);
|
||||
}
|
||||
if (this.searchForm.endTime) {
|
||||
this.searchForm.endTime = this.$filters.unixToDate(this.searchForm.endTime / 1000);
|
||||
}
|
||||
API_Shop.getBuyBillPage(this.searchForm).then((res) => {
|
||||
this.loading = false;
|
||||
if (res.success) {
|
||||
|
||||
@@ -282,7 +282,7 @@
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="结算信息" class="tab" name="settlement">
|
||||
<el-alert type="error" :closable="false" show-icon>
|
||||
<el-alert type="info" :closable="false" show-icon>
|
||||
已添加<span class="theme_color">{{ settlementCycle.length }}</span
|
||||
>个结算日,最多可添加5个结算日,当月不包含所设日期时,将会顺延到下一个结算日
|
||||
</el-alert>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { markRaw } from "vue";
|
||||
import {
|
||||
ArrowRight,
|
||||
DataAnalysis,
|
||||
@@ -40,25 +41,25 @@ const REPORT_MODULES = [
|
||||
name: "storePerformanceReport",
|
||||
title: "店铺业绩报表",
|
||||
desc: "支付金额、营业额、转化率及同环比分析",
|
||||
icon: TrendCharts,
|
||||
icon: markRaw(TrendCharts),
|
||||
},
|
||||
{
|
||||
name: "goodsComparisonReport",
|
||||
title: "商品同比环比报表",
|
||||
desc: "商品销售金额、销量占比及同环比对比",
|
||||
icon: DataAnalysis,
|
||||
icon: markRaw(DataAnalysis),
|
||||
},
|
||||
{
|
||||
name: "salesOrderDetailReport",
|
||||
title: "销售订单明细报表",
|
||||
desc: "订单流水、收款明细与优惠明细",
|
||||
icon: Document,
|
||||
icon: markRaw(Document),
|
||||
},
|
||||
{
|
||||
name: "goodsSalesSummaryReport",
|
||||
title: "商品销售汇总报表",
|
||||
desc: "商品销量、净销售额及优惠汇总",
|
||||
icon: Goods,
|
||||
icon: markRaw(Goods),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -175,9 +175,11 @@ export default {
|
||||
this.loadData();
|
||||
},
|
||||
deep: true,
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.loadData();
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.trendChart) {
|
||||
this.trendChart.destroy();
|
||||
@@ -244,6 +246,8 @@ export default {
|
||||
this.trendChart = null;
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
const container = document.getElementById("memberTrendChart");
|
||||
if (!container) return;
|
||||
this.trendChart = new Chart({
|
||||
container: "memberTrendChart",
|
||||
autoFit: true,
|
||||
@@ -280,13 +284,15 @@ export default {
|
||||
},
|
||||
async loadData() {
|
||||
const query = { ...this.params };
|
||||
const [overviewRes, analysisRes, genderRes, regionRes, trendRes] = await Promise.all([
|
||||
API_Statistics.getMemberOverview(query),
|
||||
API_Statistics.getMemberAnalysis(query),
|
||||
API_Statistics.getMemberGenderDistribution(),
|
||||
API_Statistics.getMemberRegionDistribution(),
|
||||
API_Statistics.getMemberNewTrend(query),
|
||||
]);
|
||||
const [overviewRes, analysisRes, genderRes, regionRes, trendRes] = (
|
||||
await Promise.allSettled([
|
||||
API_Statistics.getMemberOverview(query),
|
||||
API_Statistics.getMemberAnalysis(query),
|
||||
API_Statistics.getMemberGenderDistribution(),
|
||||
API_Statistics.getMemberRegionDistribution(),
|
||||
API_Statistics.getMemberNewTrend(query),
|
||||
])
|
||||
).map((r) => (r.status === "fulfilled" ? r.value : null));
|
||||
if (overviewRes && overviewRes.success) {
|
||||
this.overview = overviewRes.result || {};
|
||||
}
|
||||
|
||||
@@ -458,7 +458,6 @@ export default {
|
||||
|
||||
clickBreadcrumb(item, index) {
|
||||
let callback = JSON.parse(JSON.stringify(item));
|
||||
console.log("callback",callback)
|
||||
this.orderParams = callback;
|
||||
|
||||
this.overViewParams = callback;
|
||||
@@ -482,6 +481,8 @@ export default {
|
||||
this.chartList = res.result;
|
||||
|
||||
if (!this.orderChart) {
|
||||
const container = document.getElementById("orderChart");
|
||||
if (!container) return;
|
||||
this.orderChart = new Chart({
|
||||
container: "orderChart",
|
||||
autoFit: true,
|
||||
|
||||
@@ -1103,7 +1103,6 @@ export default {
|
||||
|
||||
|
||||
handleContextMenu(val) {
|
||||
console.log('handleContextMenu', val);
|
||||
this.selectedGroupData = val;
|
||||
},
|
||||
// 编辑分组
|
||||
@@ -1450,10 +1449,7 @@ export default {
|
||||
this.init();
|
||||
ElMessage.success("批量删除文件成功");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("失败", err);
|
||||
});
|
||||
});
|
||||
}).catch(() => {});
|
||||
},
|
||||
// 单个删除文件
|
||||
|
||||
@@ -70,7 +70,6 @@ export default {
|
||||
this.selected = v;
|
||||
getSetting(v).then((res) => {
|
||||
if (res.result) {
|
||||
console.log(res);
|
||||
this.modalVisible = true;
|
||||
this.form = res;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,16 @@ module.exports = {
|
||||
if (message.includes("ResizeObserver loop")) {
|
||||
return false;
|
||||
}
|
||||
// axios 请求错误已由拦截器统一 toast 提示,不再重复弹浮层
|
||||
if (
|
||||
error?.isAxiosError ||
|
||||
error?.name === "AxiosError" ||
|
||||
message.includes("Request failed with status code") ||
|
||||
message.includes("Network Error") ||
|
||||
message.includes("timeout of")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
@@ -78,11 +88,19 @@ module.exports = {
|
||||
args[0].cdn = { css: [], js: [] };
|
||||
return args;
|
||||
});
|
||||
if (enableProduction) {
|
||||
// 生产环境移除所有 console.* 调用
|
||||
config.optimization.minimizer("terser").tap((args) => {
|
||||
const terserOptions = args[0].terserOptions || (args[0].terserOptions = {});
|
||||
terserOptions.compress = { ...terserOptions.compress, drop_console: true };
|
||||
return args;
|
||||
});
|
||||
}
|
||||
},
|
||||
pluginOptions: {
|
||||
"style-resources-loader": {
|
||||
preProcessor: "scss",
|
||||
patterns: [path.resolve(__dirname, "./src/styles/common.scss")],
|
||||
patterns: [path.resolve(__dirname, "./src/styles/variables.scss")],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user