diff --git a/app/Domains/Real/Repositories/OrderRepository.php b/app/Domains/Real/Repositories/OrderRepository.php
index 7d5d31d5..50c1c4f9 100644
--- a/app/Domains/Real/Repositories/OrderRepository.php
+++ b/app/Domains/Real/Repositories/OrderRepository.php
@@ -2,6 +2,7 @@
namespace App\Domains\Real\Repositories;
+use Carbon\Carbon;
use App\Core\Repository;
use App\Models\Real\Order as Model;
diff --git a/frontend/src/components/table/assist.js b/frontend/src/components/table/assist.js
new file mode 100644
index 00000000..b6bd5500
--- /dev/null
+++ b/frontend/src/components/table/assist.js
@@ -0,0 +1,329 @@
+import Vue from 'vue';
+const isServer = Vue.prototype.$isServer;
+// 判断参数是否是其中之一
+export function oneOf(value, validList) {
+ for (let i = 0; i < validList.length; i++) {
+ if (value === validList[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+export function camelcaseToHyphen(str) {
+ return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
+}
+
+// For Modal scrollBar hidden
+let cached;
+export function getScrollBarSize(fresh) {
+ if (isServer) return 0;
+ if (fresh || cached === undefined) {
+ const inner = document.createElement('div');
+ inner.style.width = '100%';
+ inner.style.height = '200px';
+
+ const outer = document.createElement('div');
+ const outerStyle = outer.style;
+
+ outerStyle.position = 'absolute';
+ outerStyle.top = 0;
+ outerStyle.left = 0;
+ outerStyle.pointerEvents = 'none';
+ outerStyle.visibility = 'hidden';
+ outerStyle.width = '200px';
+ outerStyle.height = '150px';
+ outerStyle.overflow = 'hidden';
+
+ outer.appendChild(inner);
+
+ document.body.appendChild(outer);
+
+ const widthContained = inner.offsetWidth;
+ outer.style.overflow = 'scroll';
+ let widthScroll = inner.offsetWidth;
+
+ if (widthContained === widthScroll) {
+ widthScroll = outer.clientWidth;
+ }
+
+ document.body.removeChild(outer);
+
+ cached = widthContained - widthScroll;
+ }
+ return cached;
+}
+
+// watch DOM change
+export const MutationObserver = isServer ? false : window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver || false;
+
+const SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
+const MOZ_HACK_REGEXP = /^moz([A-Z])/;
+
+function camelCase(name) {
+ return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
+ return offset ? letter.toUpperCase() : letter;
+ }).replace(MOZ_HACK_REGEXP, 'Moz$1');
+}
+// getStyle
+export function getStyle(element, styleName) {
+ if (!element || !styleName) return null;
+ styleName = camelCase(styleName);
+ if (styleName === 'float') {
+ styleName = 'cssFloat';
+ }
+ try {
+ const computed = document.defaultView.getComputedStyle(element, '');
+ return element.style[styleName] || computed ? computed[styleName] : null;
+ } catch (e) {
+ return element.style[styleName];
+ }
+}
+
+// firstUpperCase
+function firstUpperCase(str) {
+ return str.toString()[0].toUpperCase() + str.toString().slice(1);
+}
+export { firstUpperCase };
+
+// Warn
+export function warnProp(component, prop, correctType, wrongType) {
+ correctType = firstUpperCase(correctType);
+ wrongType = firstUpperCase(wrongType);
+ console.error(`[iView warn]: Invalid prop: type check failed for prop ${prop}. Expected ${correctType}, got ${wrongType}. (found in component: ${component})`); // eslint-disable-line
+}
+
+function typeOf(obj) {
+ const toString = Object.prototype.toString;
+ const map = {
+ '[object Boolean]': 'boolean',
+ '[object Number]': 'number',
+ '[object String]': 'string',
+ '[object Function]': 'function',
+ '[object Array]': 'array',
+ '[object Date]': 'date',
+ '[object RegExp]': 'regExp',
+ '[object Undefined]': 'undefined',
+ '[object Null]': 'null',
+ '[object Object]': 'object'
+ };
+ return map[toString.call(obj)];
+}
+
+// deepCopy
+function deepCopy(data) {
+ const t = typeOf(data);
+ let o;
+
+ if (t === 'array') {
+ o = [];
+ } else if (t === 'object') {
+ o = {};
+ } else {
+ return data;
+ }
+
+ if (t === 'array') {
+ for (let i = 0; i < data.length; i++) {
+ o.push(deepCopy(data[i]));
+ }
+ } else if (t === 'object') {
+ for (let i in data) {
+ o[i] = deepCopy(data[i]);
+ }
+ }
+ return o;
+}
+
+export { deepCopy };
+
+// scrollTop animation
+export function scrollTop(el, from = 0, to, duration = 500, endCallback) {
+ if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = (
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) {
+ return window.setTimeout(callback, 1000 / 60);
+ }
+ );
+ }
+ const difference = Math.abs(from - to);
+ const step = Math.ceil(difference / duration * 50);
+
+ function scroll(start, end, step) {
+ if (start === end) {
+ endCallback && endCallback();
+ return;
+ }
+
+ let d = (start + step > end) ? end : start + step;
+ if (start > end) {
+ d = (start - step < end) ? end : start - step;
+ }
+
+ if (el === window) {
+ window.scrollTo(d, d);
+ } else {
+ el.scrollTop = d;
+ }
+ window.requestAnimationFrame(() => scroll(d, end, step));
+ }
+ scroll(from, to, step);
+}
+
+// Find components upward
+function findComponentUpward(context, componentName, componentNames) {
+ if (typeof componentName === 'string') {
+ componentNames = [componentName];
+ } else {
+ componentNames = componentName;
+ }
+
+ let parent = context.$parent;
+ let name = parent.$options.name;
+ while (parent && (!name || componentNames.indexOf(name) < 0)) {
+ parent = parent.$parent;
+ if (parent) name = parent.$options.name;
+ }
+ return parent;
+}
+export { findComponentUpward };
+
+// Find component downward
+export function findComponentDownward(context, componentName) {
+ const childrens = context.$children;
+ let children = null;
+
+ if (childrens.length) {
+ for (const child of childrens) {
+ const name = child.$options.name;
+ if (name === componentName) {
+ children = child;
+ break;
+ } else {
+ children = findComponentDownward(child, componentName);
+ if (children) break;
+ }
+ }
+ }
+ return children;
+}
+
+// Find components downward
+export function findComponentsDownward(context, componentName) {
+ return context.$children.reduce((components, child) => {
+ if (child.$options.name === componentName) components.push(child);
+ const foundChilds = findComponentsDownward(child, componentName);
+ return components.concat(foundChilds);
+ }, []);
+}
+
+// Find components upward
+export function findComponentsUpward(context, componentName) {
+ let parents = [];
+ const parent = context.$parent;
+ if (parent) {
+ if (parent.$options.name === componentName) parents.push(parent);
+ return parents.concat(findComponentsUpward(parent, componentName));
+ } else {
+ return [];
+ }
+}
+
+// Find brothers components
+export function findBrothersComponents(context, componentName, exceptMe = true) {
+ let res = context.$parent.$children.filter(item => {
+ return item.$options.name === componentName;
+ });
+ let index = res.findIndex(item => item._uid === context._uid);
+ if (exceptMe) res.splice(index, 1);
+ return res;
+}
+
+/* istanbul ignore next */
+const trim = function(string) {
+ return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '');
+};
+
+/* istanbul ignore next */
+export function hasClass(el, cls) {
+ if (!el || !cls) return false;
+ if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.');
+ if (el.classList) {
+ return el.classList.contains(cls);
+ } else {
+ return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1;
+ }
+}
+
+/* istanbul ignore next */
+export function addClass(el, cls) {
+ if (!el) return;
+ let curClass = el.className;
+ const classes = (cls || '').split(' ');
+
+ for (let i = 0, j = classes.length; i < j; i++) {
+ const clsName = classes[i];
+ if (!clsName) continue;
+
+ if (el.classList) {
+ el.classList.add(clsName);
+ } else {
+ if (!hasClass(el, clsName)) {
+ curClass += ' ' + clsName;
+ }
+ }
+ }
+ if (!el.classList) {
+ el.className = curClass;
+ }
+}
+
+/* istanbul ignore next */
+export function removeClass(el, cls) {
+ if (!el || !cls) return;
+ const classes = cls.split(' ');
+ let curClass = ' ' + el.className + ' ';
+
+ for (let i = 0, j = classes.length; i < j; i++) {
+ const clsName = classes[i];
+ if (!clsName) continue;
+
+ if (el.classList) {
+ el.classList.remove(clsName);
+ } else {
+ if (hasClass(el, clsName)) {
+ curClass = curClass.replace(' ' + clsName + ' ', ' ');
+ }
+ }
+ }
+ if (!el.classList) {
+ el.className = trim(curClass);
+ }
+}
+
+export const dimensionMap = {
+ xs: '480px',
+ sm: '768px',
+ md: '992px',
+ lg: '1200px',
+ xl: '1600px'
+};
+
+export function setMatchMedia() {
+ if (typeof window !== 'undefined') {
+ const matchMediaPolyfill = mediaQuery => {
+ return {
+ media: mediaQuery,
+ matches: false,
+ on() {},
+ off() {}
+ };
+ };
+ window.matchMedia = window.matchMedia || matchMediaPolyfill;
+ }
+}
+
+export const sharpMatcherRegx = /#([^#]+)$/;
diff --git a/frontend/src/components/table/cell.vue b/frontend/src/components/table/cell.vue
new file mode 100644
index 00000000..f30ad940
--- /dev/null
+++ b/frontend/src/components/table/cell.vue
@@ -0,0 +1,137 @@
+
+
+
+ {{ column.indexMethod ? column.indexMethod(row) : (naturalIndex + 1) }}
+
+
+
+
+
+
+
+
+
+
+ {{ row[column.key] }}
+
+
+ {{row[column.key]}}
+
+
+
+
+
+
+
|
+
+
+
diff --git a/frontend/src/components/table/csv.js b/frontend/src/components/table/csv.js
new file mode 100644
index 00000000..b0605415
--- /dev/null
+++ b/frontend/src/components/table/csv.js
@@ -0,0 +1,59 @@
+/*
+ inspired by https://www.npmjs.com/package/react-csv-downloader
+ now removed from Github
+*/
+
+const newLine = '\r\n';
+const appendLine = (content, row, { separator, quoted }) => {
+ const line = row.map(data => {
+ if (!quoted) return data;
+ // quote data
+ data = typeof data === 'string' ? data.replace(/"/g, '"') : data;
+ return `"${data}"`;
+ });
+ content.push(line.join(separator));
+};
+
+const defaults = {
+ separator: ',',
+ quoted: false
+};
+
+export default function csv(columns, datas, options, noHeader = false) {
+ options = Object.assign({}, defaults, options);
+ let columnOrder;
+ const content = [];
+ const column = [];
+
+ if (columns) {
+ columnOrder = columns.map(v => {
+ if (typeof v === 'string') return v;
+ if (!noHeader) {
+ column.push(typeof v.title !== 'undefined' ? v.title : v.key);
+ }
+ return v.key;
+ });
+ if (column.length > 0) appendLine(content, column, options);
+ } else {
+ columnOrder = [];
+ datas.forEach(v => {
+ if (!Array.isArray(v)) {
+ columnOrder = columnOrder.concat(Object.keys(v));
+ }
+ });
+ if (columnOrder.length > 0) {
+ columnOrder = columnOrder.filter((value, index, self) => self.indexOf(value) === index);
+ if (!noHeader) appendLine(content, columnOrder, options);
+ }
+ }
+
+ if (Array.isArray(datas)) {
+ datas.forEach(row => {
+ if (!Array.isArray(row)) {
+ row = columnOrder.map(k => (typeof row[k] !== 'undefined' ? row[k] : ''));
+ }
+ appendLine(content, row, options);
+ });
+ }
+ return content.join(newLine);
+}
diff --git a/frontend/src/components/table/dom.js b/frontend/src/components/table/dom.js
new file mode 100644
index 00000000..26a228e0
--- /dev/null
+++ b/frontend/src/components/table/dom.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+const isServer = Vue.prototype.$isServer;
+
+/* istanbul ignore next */
+export const on = (function() {
+ if (!isServer && document.addEventListener) {
+ return function(element, event, handler) {
+ if (element && event && handler) {
+ element.addEventListener(event, handler, false);
+ }
+ };
+ } else {
+ return function(element, event, handler) {
+ if (element && event && handler) {
+ element.attachEvent('on' + event, handler);
+ }
+ };
+ }
+})();
+
+/* istanbul ignore next */
+export const off = (function() {
+ if (!isServer && document.removeEventListener) {
+ return function(element, event, handler) {
+ if (element && event) {
+ element.removeEventListener(event, handler, false);
+ }
+ };
+ } else {
+ return function(element, event, handler) {
+ if (element && event) {
+ element.detachEvent('on' + event, handler);
+ }
+ };
+ }
+})();
diff --git a/frontend/src/components/table/expand.js b/frontend/src/components/table/expand.js
new file mode 100644
index 00000000..2c855946
--- /dev/null
+++ b/frontend/src/components/table/expand.js
@@ -0,0 +1,21 @@
+export default {
+ name: 'TableExpand',
+ functional: true,
+ props: {
+ row: Object,
+ render: Function,
+ index: Number,
+ column: {
+ type: Object,
+ default: null
+ }
+ },
+ render: (h, ctx) => {
+ const params = {
+ row: ctx.props.row,
+ index: ctx.props.index
+ };
+ if (ctx.props.column) params.column = ctx.props.column;
+ return ctx.props.render(h, params);
+ }
+};
diff --git a/frontend/src/components/table/export-csv.js b/frontend/src/components/table/export-csv.js
new file mode 100644
index 00000000..c76c726f
--- /dev/null
+++ b/frontend/src/components/table/export-csv.js
@@ -0,0 +1,76 @@
+function has(browser) {
+ const ua = navigator.userAgent;
+ if (browser === 'ie') {
+ const isIE = ua.indexOf('compatible') > -1 && ua.indexOf('MSIE') > -1;
+ if (isIE) {
+ const reIE = new RegExp('MSIE (\\d+\\.\\d+);');
+ reIE.test(ua);
+ return parseFloat(RegExp['$1']);
+ } else {
+ return false;
+ }
+ } else {
+ return ua.indexOf(browser) > -1;
+ }
+}
+
+const csv = {
+ _isIE11() {
+ let iev = 0;
+ const ieold = (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
+ const trident = !!navigator.userAgent.match(/Trident\/7.0/);
+ const rv = navigator.userAgent.indexOf('rv:11.0');
+
+ if (ieold) {
+ iev = Number(RegExp.$1);
+ }
+ if (navigator.appVersion.indexOf('MSIE 10') !== -1) {
+ iev = 10;
+ }
+ if (trident && rv !== -1) {
+ iev = 11;
+ }
+
+ return iev === 11;
+ },
+
+ _isEdge() {
+ return /Edge/.test(navigator.userAgent);
+ },
+
+ _getDownloadUrl(text) {
+ const BOM = '\uFEFF';
+ // Add BOM to text for open in excel correctly
+ if (window.Blob && window.URL && window.URL.createObjectURL) {
+ const csvData = new Blob([BOM + text], { type: 'text/csv' });
+ return URL.createObjectURL(csvData);
+ } else {
+ return 'data:attachment/csv;charset=utf-8,' + BOM + encodeURIComponent(text);
+ }
+ },
+
+ download(filename, text) {
+ if (has('ie') && has('ie') < 10) {
+ // has module unable identify ie11 and Edge
+ const oWin = window.top.open('about:blank', '_blank');
+ oWin.document.charset = 'utf-8';
+ oWin.document.write(text);
+ oWin.document.close();
+ oWin.document.execCommand('SaveAs', filename);
+ oWin.close();
+ } else if (has('ie') === 10 || this._isIE11() || this._isEdge()) {
+ const BOM = '\uFEFF';
+ const csvData = new Blob([BOM + text], { type: 'text/csv' });
+ navigator.msSaveBlob(csvData, filename);
+ } else {
+ const link = document.createElement('a');
+ link.download = filename;
+ link.href = this._getDownloadUrl(text);
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ }
+ }
+};
+
+export default csv;
diff --git a/frontend/src/components/table/header.js b/frontend/src/components/table/header.js
new file mode 100644
index 00000000..0c31c6ac
--- /dev/null
+++ b/frontend/src/components/table/header.js
@@ -0,0 +1,16 @@
+export default {
+ name: 'TableRenderHeader',
+ functional: true,
+ props: {
+ render: Function,
+ column: Object,
+ index: Number
+ },
+ render: (h, ctx) => {
+ const params = {
+ column: ctx.props.column,
+ index: ctx.props.index
+ };
+ return ctx.props.render(h, params);
+ }
+};
diff --git a/frontend/src/components/table/index.js b/frontend/src/components/table/index.js
new file mode 100644
index 00000000..087b4c9e
--- /dev/null
+++ b/frontend/src/components/table/index.js
@@ -0,0 +1,2 @@
+import Table from './table.vue';
+export default Table;
diff --git a/frontend/src/components/table/mixin.js b/frontend/src/components/table/mixin.js
new file mode 100644
index 00000000..ecafae2d
--- /dev/null
+++ b/frontend/src/components/table/mixin.js
@@ -0,0 +1,31 @@
+export default {
+ methods: {
+ alignCls(column, row = {}) {
+ let cellClassName = '';
+ if (row.cellClassName && column.key && row.cellClassName[column.key]) {
+ cellClassName = row.cellClassName[column.key];
+ }
+ return [
+ {
+ [`${cellClassName}`]: cellClassName, // cell className
+ [`${column.className}`]: column.className, // column className
+ [`${this.prefixCls}-column-${column.align}`]: column.align,
+ [`${this.prefixCls}-hidden`]: (this.fixed === 'left' && column.fixed !== 'left') || (this.fixed === 'right' && column.fixed !== 'right') || (!this.fixed && column.fixed && (column.fixed === 'left' || column.fixed === 'right'))
+ }
+ ];
+ },
+ isPopperShow(column) {
+ return column.filters && ((!this.fixed && !column.fixed) || (this.fixed === 'left' && column.fixed === 'left') || (this.fixed === 'right' && column.fixed === 'right'));
+ },
+ setCellWidth(column) {
+ let width = '';
+ if (column.width) {
+ width = column.width;
+ } else if (this.columnsWidth[column._index]) {
+ width = this.columnsWidth[column._index].width;
+ }
+ if (width === '0') width = '';
+ return width;
+ }
+ }
+};
diff --git a/frontend/src/components/table/table-body.vue b/frontend/src/components/table/table-body.vue
new file mode 100644
index 00000000..6dc5ad85
--- /dev/null
+++ b/frontend/src/components/table/table-body.vue
@@ -0,0 +1,245 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/table/table-head.vue b/frontend/src/components/table/table-head.vue
new file mode 100644
index 00000000..e5877e0c
--- /dev/null
+++ b/frontend/src/components/table/table-head.vue
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ column.title || '' }}
+
+
+
+
+
+
+ {{ column.title || '#' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ item.label }}
+
+
+
+ {{ t('i.table.confirmFilter') }}
+ {{ t('i.table.resetFilter') }}
+
+
+
+
+ - {{ t('i.table.clearFilter') }}
+ - {{ item.label }}
+
+
+
+
+
+ |
+
+ |
+
+
+
+
+
diff --git a/frontend/src/components/table/table-tr.vue b/frontend/src/components/table/table-tr.vue
new file mode 100644
index 00000000..8d07bfec
--- /dev/null
+++ b/frontend/src/components/table/table-tr.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
diff --git a/frontend/src/components/table/table.vue b/frontend/src/components/table/table.vue
new file mode 100644
index 00000000..f4d0394b
--- /dev/null
+++ b/frontend/src/components/table/table.vue
@@ -0,0 +1,1081 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/table/util.js b/frontend/src/components/table/util.js
new file mode 100644
index 00000000..c45d51a7
--- /dev/null
+++ b/frontend/src/components/table/util.js
@@ -0,0 +1,93 @@
+import { deepCopy } from './assist';
+
+const convertColumnOrder = (columns, fixedType) => {
+ let list = [];
+ let other = [];
+ columns.forEach((col) => {
+ if (col.fixed && col.fixed === fixedType) {
+ list.push(col);
+ } else {
+ other.push(col);
+ }
+ });
+ return list.concat(other);
+};
+
+export { convertColumnOrder };
+
+// set forTableHead to true when convertToRows, false in normal cases like table.vue
+const getAllColumns = (cols, forTableHead = false) => {
+ const columns = deepCopy(cols);
+ const result = [];
+ columns.forEach((column) => {
+ if (column.children) {
+ if (forTableHead) result.push(column);
+ result.push.apply(result, getAllColumns(column.children, forTableHead));
+ } else {
+ result.push(column);
+ }
+ });
+ return result;
+};
+
+export { getAllColumns };
+
+const convertToRows = (columns, fixedType = false) => {
+ const originColumns = fixedType ? fixedType === 'left' ? deepCopy(convertColumnOrder(columns, 'left')) : deepCopy(convertColumnOrder(columns, 'right')) : deepCopy(columns);
+ let maxLevel = 1;
+ const traverse = (column, parent) => {
+ if (parent) {
+ column.level = parent.level + 1;
+ if (maxLevel < column.level) {
+ maxLevel = column.level;
+ }
+ }
+ if (column.children) {
+ let colSpan = 0;
+ column.children.forEach((subColumn) => {
+ traverse(subColumn, column);
+ colSpan += subColumn.colSpan;
+ });
+ column.colSpan = colSpan;
+ } else {
+ column.colSpan = 1;
+ }
+ };
+
+ originColumns.forEach((column) => {
+ column.level = 1;
+ traverse(column);
+ });
+
+ const rows = [];
+ for (let i = 0; i < maxLevel; i++) {
+ rows.push([]);
+ }
+
+ const allColumns = getAllColumns(originColumns, true);
+
+ allColumns.forEach((column) => {
+ if (!column.children) {
+ column.rowSpan = maxLevel - column.level + 1;
+ } else {
+ column.rowSpan = 1;
+ }
+ rows[column.level - 1].push(column);
+ });
+
+ return rows;
+};
+
+export { convertToRows };
+
+const getRandomStr = function(len = 32) {
+ const $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
+ const maxPos = $chars.length;
+ let str = '';
+ for (let i = 0; i < len; i++) {
+ str += $chars.charAt(Math.floor(Math.random() * maxPos));
+ }
+ return str;
+};
+
+export { getRandomStr };
diff --git a/frontend/src/components/vue-bigdata-table/components/button.vue b/frontend/src/components/vue-bigdata-table/components/button.vue
new file mode 100644
index 00000000..a4a473c3
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/components/button.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
diff --git a/frontend/src/components/vue-bigdata-table/components/input-render.js b/frontend/src/components/vue-bigdata-table/components/input-render.js
new file mode 100644
index 00000000..6f0f28cc
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/components/input-render.js
@@ -0,0 +1,59 @@
+import Input from './input.vue';
+import Button from './button.vue';
+export default (h, { row, col, value, beforeSave, initRowIndex }, table) => {
+ return h('div', {
+ 'class': 'edit-item-con'
+ }, [
+ h(Input, {
+ 'class': 'edit-item-input',
+ props: {
+ value: value
+ },
+ on: {
+ input(res) {
+ table.editContent = res;
+ }
+ }
+ }),
+ h('div', {
+ 'class': 'edit-item-btn-con'
+ }, [
+ h(Button, {
+ 'class': 'edit-btn',
+ props: {
+ type: 'confirm'
+ },
+ on: {
+ click() {
+ if (beforeSave({ row, col, value, initRowIndex })) {
+ table.$emit('on-success-save', {
+ row: row,
+ col: col,
+ value: table.editContent,
+ initRowIndex: initRowIndex
+ });
+ } else {
+ table.$emit('on-fail-save', {
+ row: row,
+ col: col,
+ value: table.editContent,
+ initRowIndex: initRowIndex
+ });
+ }
+ }
+ }
+ }),
+ h(Button, {
+ 'class': 'edit-btn',
+ props: {
+ type: 'cancel'
+ },
+ on: {
+ click() {
+ table.$emit('on-cancel-edit');
+ }
+ }
+ })
+ ])
+ ]);
+};
diff --git a/frontend/src/components/vue-bigdata-table/components/input.vue b/frontend/src/components/vue-bigdata-table/components/input.vue
new file mode 100644
index 00000000..7b68ab32
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/components/input.vue
@@ -0,0 +1,46 @@
+
+
+
+
+
diff --git a/frontend/src/components/vue-bigdata-table/components/item-table.vue b/frontend/src/components/vue-bigdata-table/components/item-table.vue
new file mode 100755
index 00000000..ce8911c9
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/components/item-table.vue
@@ -0,0 +1,279 @@
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+ {{ (typeof td === 'object' && td !== null) ? td.value : td }}
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+ {{ (typeof td === 'object' && td !== null) ? td.value : td }}
+
+
+
+
+
+ |
+
+
+
+
+
+
diff --git a/frontend/src/components/vue-bigdata-table/components/renderDom.js b/frontend/src/components/vue-bigdata-table/components/renderDom.js
new file mode 100644
index 00000000..75649b7a
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/components/renderDom.js
@@ -0,0 +1,11 @@
+export default {
+ name: 'RenderCell',
+ functional: true,
+ props: {
+ render: Function,
+ backValue: [Number, Object]
+ },
+ render: (h, ctx) => {
+ return ctx.props.render(h, ctx.props.backValue, ctx.parent);
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/components/sort-button.vue b/frontend/src/components/vue-bigdata-table/components/sort-button.vue
new file mode 100644
index 00000000..a4dc8fc5
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/components/sort-button.vue
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
diff --git a/frontend/src/components/vue-bigdata-table/index.js b/frontend/src/components/vue-bigdata-table/index.js
new file mode 100644
index 00000000..25dd4ff8
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/index.js
@@ -0,0 +1,2 @@
+import bigdataTable from './vue-bigdata-table.vue';
+export default bigdataTable;
diff --git a/frontend/src/components/vue-bigdata-table/mixins/data-handle.js b/frontend/src/components/vue-bigdata-table/mixins/data-handle.js
new file mode 100644
index 00000000..2efdde3d
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/data-handle.js
@@ -0,0 +1,217 @@
+import ItemTable from '../components/item-table.vue';
+import { iteratorByTimes, getHeaderWords } from '../util';
+export default {
+ data() {
+ return {
+ times0: 0, // 当前是第几轮
+ times1: 0,
+ times2: -1,
+ table1Data: [],
+ table2Data: [],
+ table3Data: [],
+ currentIndex: 0, // 当前展示的表格是第几个
+ itemNum: 0, // 一块数据显示的数据条数
+ timer: null,
+ scrollLeft: 0,
+ insideTableData: [],
+ initTableData: [] // 初始表格数据,用于恢复搜索和筛选,
+ };
+ },
+ computed: {
+ cellNum() { // 表格列数
+ return this.columnsHandled.length;
+ },
+ columnsHandled() {
+ let columns = [...this.columns];
+ if (this.colNum > this.columns.length) {
+ let colLength = this.colNum - this.columns.length;
+ let headerWordsArr = getHeaderWords(colLength);
+ iteratorByTimes(colLength, (i) => {
+ columns.push({
+ title: headerWordsArr[i]
+ });
+ });
+ }
+ if (this.showIndex) {
+ columns.unshift({
+ title: 'No',
+ align: 'center',
+ width: this.indexWidthInside
+ });
+ }
+ return columns;
+ }
+ },
+ methods: {
+ getComputedTableDataIndex(colIndex) {
+ return this.showIndex ? (colIndex - 1) : colIndex;
+ },
+ handleScroll(e) {
+ let ele = e.srcElement || e.target;
+ let { scrollTop, scrollLeft } = ele;
+ this.scrollLeft = scrollLeft;
+ // let direction = (scrollTop - this.scrollTop) > 0 ? 1 : ((scrollTop - this.scrollTop) < 0 ? -1 : 0); // 1 => down -1 => up 0 => stop
+ this.currentIndex = parseInt((scrollTop % (this.moduleHeight * 3)) / this.moduleHeight);
+ this.scrollTop = scrollTop;
+ this.$nextTick(() => {
+ this.setTopPlace();
+ });
+ },
+ setTableData() {
+ let count1 = this.times0 * this.itemNum * 3;
+ this.table1Data = this.insideTableData.slice(count1, count1 + this.itemNum);
+ let count2 = this.times1 * this.itemNum * 3;
+ this.table2Data = this.insideTableData.slice(count2 + this.itemNum, count2 + this.itemNum * 2);
+ let count3 = this.times2 * this.itemNum * 3;
+ this.table3Data = this.insideTableData.slice(count3 + this.itemNum * 2, count3 + this.itemNum * 3);
+ },
+ getTables(h) {
+ let table1 = this.getItemTable(h, this.table1Data, 1);
+ let table2 = this.getItemTable(h, this.table2Data, 2);
+ let table3 = this.getItemTable(h, this.table3Data, 3);
+ if (this.currentIndex === 0) {
+ return [table1, table2, table3];
+ } else if (this.currentIndex === 1) {
+ return [table2, table3, table1];
+ } else {
+ return [table3, table1, table2];
+ }
+ },
+ renderTable(h) {
+ return h('div', {
+ style: this.tableWidthStyles
+ }, this.getTables(h));
+ },
+ getItemTable(h, data, index) {
+ return h(ItemTable, {
+ props: {
+ times: this['times' + (index - 1)],
+ tableIndex: index,
+ itemData: data,
+ itemNum: this.itemNum,
+ rowStyles: this.rowStyles,
+ widthArr: this.colWidthArr,
+ columns: this.columnsHandled,
+ showIndex: this.showIndex,
+ indexRender: this.indexRender,
+ stripe: this.stripe,
+ fixedCol: this.fixedCol,
+ currentScrollToRowIndex: this.currentScrollToRowIndex,
+ canEdit: this.canEdit,
+ edittingTd: this.edittingTd,
+ startEditType: this.startEditType,
+ showFixedBoxShadow: this.showFixedBoxShadow,
+ editCellRender: this.editCellRender,
+ beforeSave: this.beforeSave,
+ canSelectText: this.canSelectText,
+ startSelect: this.startSelect,
+ endSelect: this.endSelect,
+ disabledHover: this.disabledHover,
+ highlightRow: this.highlightRow,
+ highlightRowIndex: this.highlightRowIndex,
+ indexRenderParams: this.indexRenderParams
+ },
+ on: {
+ 'on-click-tr': (index, initRowIndex) => {
+ if (this.highlightRow) this.highlightRowIndex = index;
+ this.$emit('on-click-tr', index, initRowIndex);
+ },
+ 'on-click-td': (params) => {
+ this.$emit('on-click-td', params);
+ },
+ 'on-edit-cell': (row, col) => {
+ // this.edittingTd = `${row}-${col}`;
+ this._editCell(row, col, false);
+ },
+ 'on-success-save': ({ row, col, value, initRowIndex, oldValue }) => {
+ let data = [...this.value];
+ data[initRowIndex][col] = value;
+ this.$emit('input', data);
+ this.$emit('on-success-save', { row, col, value, initRowIndex, oldValue });
+ this.edittingTd = '';
+ },
+ 'on-fail-save': ({ row, col, value, initRowIndex }) => {
+ this.$emit('on-fail-save', { row, col, value, initRowIndex });
+ },
+ 'on-cancel-edit': () => {
+ this.edittingTd = '';
+ },
+ 'on-paste': (data) => {
+ if (!this.paste) return;
+ let value = [...this.value];
+ let rowLength = data.length;
+ let startSelect = this.startSelect;
+ let endSelect = this.endSelect;
+ let startRow = startSelect.row;
+ let startCol = startSelect.col;
+ let endRow = endSelect.row;
+ let endCol = endSelect.col;
+ let selectRow = endRow - startRow + 1;
+ let selectCol = endCol - startCol + 1;
+ // let lastColLength = value[0].length - startCol;
+ // let lastRowLength = value.length - startRow;
+ if (rowLength === 0) return;
+ let colLength = data[0].length;
+ if (colLength === 0) return;
+ // 使用复制的数据替换原数据
+ for (let r = 0; r < rowLength && r < selectRow; r++) {
+ for (let c = 0; c < colLength && c < selectCol; c++) {
+ let valueRow = startRow + r;
+ let valueCol = startCol + c;
+ if (typeof value[valueRow][valueCol] === 'object') {
+ value[valueRow][valueCol].value = data[r][c];
+ } else {
+ value[valueRow][valueCol] = data[r][c];
+ }
+ }
+ }
+ // for (let r = startRow; r < selectRow; r++) {
+ // for (let c = startCol; c < selectCol; c++) {
+ // //
+ // }
+ // }
+ this.$emit('input', value);
+ this.$emit('on-paste', data);
+ this._tableResize();
+ }
+ },
+ key: 'table-item-key' + index,
+ ref: 'itemTable' + index,
+ attrs: {
+ 'data-index': index
+ }
+ });
+ },
+ _scrollToIndexRow(index) {
+ index = parseInt(index);
+ if (isNaN(index) || index >= this.insideTableData.length || index < 0) return;
+ let scrollTop = index * this.itemRowHeight;
+ this.$refs.outer.scrollTop = scrollTop;
+ this.currentScrollToRowIndex = index;
+ clearTimeout(this.timer);
+ this.timer = setTimeout(() => {
+ this.currentScrollToRowIndex = -1;
+ }, 1800);
+ },
+ // 给表格数据添加行号,用于排序后正确修改数据
+ setInitIndex(tableData) {
+ return tableData.map((item, i) => {
+ let row = item;
+ row.initRowIndex = i;
+ return row;
+ });
+ },
+ // 获取指定行的初始行号
+ _getInitRowIndexByIndex(index) {
+ return this.insideTableData[index].initRowIndex;
+ },
+ _getIndexByInitRowIndex(index) {
+ let i = -1;
+ let len = this.insideTableData.length;
+ while (++i < len) {
+ let row = this.insideTableData[i];
+ if (row.initRowIndex === index) return i;
+ }
+ }
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/mixins/edit.js b/frontend/src/components/vue-bigdata-table/mixins/edit.js
new file mode 100644
index 00000000..0ba5d304
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/edit.js
@@ -0,0 +1,90 @@
+import { findNodeUpper } from '../util';
+export default {
+ data() {
+ return {
+ edittingTd: '', // 正在编辑的单元格的行号和列号拼接的字符串 `${row}-${col}`
+ editContent: '', // 用来保存编辑的内容
+ selectCellsStart: {}, // 编辑模式下可选中多行多列,此用来保存其实单元格行列号
+ selectCellsEnd: {},
+ selectTotalColStartIndex: -1, // 选取整列起始序列号
+ selectTotalColEndIndex: -1
+ };
+ },
+ computed: {
+ startSelect() {
+ return {
+ row: Math.min(this.selectCellsStart.row, this.selectCellsEnd.row),
+ col: Math.min(this.selectCellsStart.col, this.selectCellsEnd.col)
+ };
+ },
+ endSelect() {
+ return {
+ row: Math.max(this.selectCellsStart.row, this.selectCellsEnd.row),
+ col: Math.max(this.selectCellsStart.col, this.selectCellsEnd.col)
+ };
+ }
+ },
+ watch: {
+ selectable() {
+ this.selectCellsStart = {
+ row: -1,
+ col: -1
+ };
+ this.selectCellsEnd = {
+ row: -1,
+ col: -1
+ };
+ }
+ },
+ methods: {
+ _editCell(row, col, scrollToView = true) {
+ if (!this.canEdit || row < 0 || row > this.insideTableData.length || col < 0 || col > this.columns.length || this.edittingTd === `${row}-${col}`) return;
+ if (scrollToView && parseInt(this.edittingTd.split('-')[0]) !== row) this.scrollToRow(row);
+ this.edittingTd = `${row}-${col}`;
+ },
+ handleMousedownOnTable(e) {
+ if (e.button !== 0 || (!this.paste && !this.selectable)) return;
+ let currentTd = e.target.tagName === 'TD' ? e.target : findNodeUpper(e.target, 'td');
+ this.selectCellsStart = {
+ row: currentTd.getAttribute('data-row'),
+ col: currentTd.getAttribute('data-col')
+ };
+ this.selectCellsEnd = {
+ row: currentTd.getAttribute('data-row'),
+ col: currentTd.getAttribute('data-col')
+ };
+ this.canSelectText = false;
+ document.addEventListener('mousemove', this.handleMoveOnTable);
+ document.addEventListener('mouseup', this.handleUpOnTable);
+ },
+ handleMoveOnTable(e) {
+ if (!(e.target.tagName === 'TD' || findNodeUpper(e.target, 'td'))) return;
+ let currentTd = e.target.tagName === 'TD' ? e.target : findNodeUpper(e.target, 'td');
+ this.selectCellsEnd = {
+ row: currentTd.getAttribute('data-row'),
+ col: currentTd.getAttribute('data-col')
+ };
+ },
+ handleUpOnTable(e) {
+ if (!this.paste && !this.selectable) return;
+ this.canSelectText = true;
+ this.handleMoveOnTable(e);
+ document.removeEventListener('mousemove', this.handleMoveOnTable);
+ document.removeEventListener('mouseup', this.handleUpOnTable);
+ this.$emit('on-select-cells', {
+ start: {
+ row: this.startSelect.row,
+ col: this.startSelect.col
+ },
+ end: {
+ row: this.endSelect.row,
+ col: this.endSelect.col
+ }
+ });
+ },
+ _selectCell(row, col) {
+ this.selectCellsStart = { row, col };
+ this.selectCellsEnd = { row, col };
+ }
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/mixins/empty-table.js b/frontend/src/components/vue-bigdata-table/mixins/empty-table.js
new file mode 100644
index 00000000..221f7cd1
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/empty-table.js
@@ -0,0 +1,31 @@
+export default {
+ methods: {
+ _createEmptyData() {
+ // this.$nextTick(() => {
+ let rowNum = this.rowNum;
+ let colNum = this.colNum;
+ if (this.rowNum && this.colNum) {
+ console.log(this.value.length, this.rowNum, this.colNum);
+ let valueRowNum = this.value.length;
+ let valueColNum = this.value[0] ? this.value[0].length : 0;
+ let totalRowNum = valueRowNum + rowNum;
+ let totalColNum = valueColNum + colNum;
+ let value = [...this.value];
+ console.log(totalRowNum, valueRowNum);
+ for (let r = valueRowNum; r < totalRowNum; r++) {
+ value.push([]);
+ for (let c = valueColNum; c < totalColNum; c++) {
+ value[r].push('');
+ }
+ }
+ // this.
+ console.log(value);
+ this.$emit('input', value);
+ // this.$nextTick(() => {
+ // this._tableResize();
+ // })
+ }
+ // });
+ }
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/mixins/filter.js b/frontend/src/components/vue-bigdata-table/mixins/filter.js
new file mode 100644
index 00000000..bcb2c13f
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/filter.js
@@ -0,0 +1,14 @@
+import { hasOneOf } from '../util';
+export default {
+ methods: {
+ _filter(col, queryArr) {
+ let value = [...this.value];
+ this.insideTableData = value.filter(item => hasOneOf(item[col], queryArr));
+ this._tableResize();
+ },
+ _cancelFilter() {
+ this.insideTableData = [...this.value];
+ this._tableResize();
+ }
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/mixins/header-move.js b/frontend/src/components/vue-bigdata-table/mixins/header-move.js
new file mode 100644
index 00000000..cb03dc63
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/header-move.js
@@ -0,0 +1,65 @@
+import { findNodeUpper } from '../util';
+export default {
+ data() {
+ return {
+ isOnCellEdge: false, // 鼠标是否在表头的两个单元格之间的边框上
+ canResizeCell: false,
+ initCellX: 0, // 用于计算鼠标移动的距离
+ scrollLeft: 0,
+ colIndex: 0, // 在表头上移动时鼠标所在列的序号,
+ atLeftGivenArea: false, // 是否在表头单元格指定区域(距左侧)
+ atRightGivenArea: false // 是否在表头单元格指定区域(距右侧)
+ };
+ },
+ methods: {
+ handleMousemove(e) {
+ const target = e.srcElement || e.target;
+ let cell = target.tagName.toUpperCase() === 'TH' ? target : findNodeUpper(target, 'th');
+ let cellDomRect = cell.getBoundingClientRect();
+ let atLeft = (e.pageX - cellDomRect.left) < (cellDomRect.width / 2);
+ let atLeftGivenArea = (cellDomRect.left + this.atLeftCellPosi) >= e.pageX;
+ let atRightGivenArea = (cellDomRect.right - e.pageX) <= this.atRightCellPosi;
+ let cellIndex = parseInt(cell.getAttribute('data-index')); // 当前单元格的序号
+ if (atLeft && cellIndex !== 0) {
+ this.isOnCellEdge = (e.pageX - cellDomRect.left) <= 1 && cellIndex - 1 !== this.fixedCol;
+ } else if (!atLeft && cellIndex !== this.cellNum - 1) {
+ this.isOnCellEdge = (cellDomRect.right - e.pageX) <= 1 && cellIndex !== this.fixedCol;
+ }
+ e.atRightGivenArea = atRightGivenArea;
+ e.atLeftGivenArea = atLeftGivenArea;
+ this.atRightGivenArea = atRightGivenArea;
+ this.atLeftGivenArea = atLeftGivenArea;
+ let index = 0; // 调整表格列宽的左侧的表格的序列
+ e.colIndex = cellIndex;
+ this.colIndex = cellIndex;
+ this.$emit('on-moving-on-header', e);
+ if (this.canResizeCell) {
+ if (atLeft) {
+ index = cellIndex - 1;
+ } else {
+ index = cellIndex;
+ }
+ if (index === this.fixedCol) return;
+ let widthLeft = this.widthArr[index] + e.pageX - this.initCellX;
+ let widthRight = this.widthArr[index + 1] + this.initCellX - e.pageX;
+ this.widthArr.splice(index, 2, widthLeft, widthRight);
+ this.initCellX = e.pageX;
+ }
+ },
+ handleMousedown(e) {
+ e.colIndex = this.cellIndex;
+ this.$emit('on-mousedown-on-header', e);
+ if (this.isOnCellEdge) {
+ this.canResizeCell = true;
+ this.initCellX = e.pageX;
+ }
+ },
+ canNotMove(e) {
+ this.canResizeCell = false;
+ e.colIndex = this.colIndex;
+ e.atLeftGivenArea = this.atLeftGivenArea;
+ e.atRightGivenArea = this.atRightGivenArea;
+ this.$emit('on-mouseup-on-header', e);
+ }
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/mixins/index.js b/frontend/src/components/vue-bigdata-table/mixins/index.js
new file mode 100644
index 00000000..426f0de6
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/index.js
@@ -0,0 +1,9 @@
+import headerMove from './header-move';
+import styleComputed from './style-compute';
+import dataHandle from './data-handle';
+import edit from './edit';
+import emptyTable from './empty-table';
+import sort from './sort';
+import filter from './filter';
+
+export default [headerMove, styleComputed, dataHandle, edit, emptyTable, sort, filter];
diff --git a/frontend/src/components/vue-bigdata-table/mixins/sort.js b/frontend/src/components/vue-bigdata-table/mixins/sort.js
new file mode 100644
index 00000000..d30daa30
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/sort.js
@@ -0,0 +1,40 @@
+import { sortArr, sortDesArr } from '../util';
+export default {
+ data() {
+ return {
+ sortedByColIndex: -1,
+ sortedType: ''
+ };
+ },
+ methods: {
+ showSortBtn(colIndex) {
+ const sortable = this.sortable ? true : this.sortIndex !== undefined;
+ return (sortable && !(this.showIndex && colIndex === 0) && (typeof this.sortIndex === 'number' ? colIndex <= this.sortIndex : this.sortIndex.indexOf(colIndex) >= 0)) || this.columnsHandled[colIndex].sortable;
+ },
+ handleSort(colIndex, sortType) {
+ this.sortedByColIndex = colIndex;
+ this.sortedType = sortType;
+ let valueArr = [...this.value];
+ colIndex = this.showIndex ? colIndex - 1 : colIndex;
+ if (sortType === 'up') {
+ sortArr(valueArr, colIndex);
+ } else {
+ sortDesArr(valueArr, colIndex);
+ }
+ this.insideTableData = [...valueArr];
+ },
+ handleCancelSort() {
+ this.sortedByColIndex = -1;
+ this.sortedType = '';
+ this.insideTableData = [...this.value];
+ },
+ initSort() {
+ if (this.defaultSort) {
+ const colIndex = parseInt(Object.keys(this.defaultSort)[0]);
+ if (!(colIndex || colIndex === 0)) return;
+ const sortType = this.defaultSort[colIndex];
+ this.handleSort(colIndex, sortType);
+ }
+ }
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/mixins/style-compute.js b/frontend/src/components/vue-bigdata-table/mixins/style-compute.js
new file mode 100644
index 00000000..f7958a1b
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/mixins/style-compute.js
@@ -0,0 +1,202 @@
+import { getScrollbarWidth } from '../util';
+export default {
+ data() {
+ return {
+ wrapperHeight: 0,
+ scrollTop: 0,
+ moduleHeight: 0, // 三个tr块中的一块的高度
+ topPlaceholderHeight: 0, // 顶部占位容器高度
+ tableWidth: 0,
+ widthArr: [], // 用于给数据表格传递列宽
+ totalRowHeight: 0, // 如果全量渲染应该是多高,用于计算占位
+ currentScrollToRowIndex: -1, // 当前跳转到的行号,用于做闪烁提示
+ canSelectText: true, // 用于控制是否可选中表格文字
+ indexWidthInside: 0,
+ outerWidth: 0, // 外面容器宽度
+ oldTableWidth: 0, // 旧的表格宽度,用于重新计算列宽
+ highlightRowIndex: -1, // 高亮行号
+ updateID: 0
+ };
+ },
+ computed: {
+ fixedColCom() {
+ return this.showIndex ? (this.fixedCol + 1) : this.fixedCol;
+ },
+ wrapperClasses() {
+ return [
+ this.prefix,
+ this.fixed ? `${this.prefix}-fixed` : ''
+ ];
+ },
+ headerStyle() {
+ return {
+ height: this.headerHeight + 'px',
+ transform: 'translateX(0)'
+ };
+ },
+ showFixedBoxShadow() {
+ return this.scrollLeft !== 0;
+ },
+ tableWidthStyles() {
+ return { width: this.tableWidth + 'px' };
+ },
+ rowStyles() {
+ return this.rowHeight !== undefined ? { height: `${this.rowHeight}px` } : {};
+ },
+ placeholderHeight() {
+ return this.totalRowHeight - this.moduleHeight * 3; // 占位容器的总高度(上 + 下)
+ },
+ bottomPlaceholderHeight() {
+ return (this.placeholderHeight - this.topPlaceholderHeight) < 0 ? 0 : this.placeholderHeight - this.topPlaceholderHeight;
+ },
+ itemRowHeight() {
+ return this.rowHeight === undefined ? 48 : this.rowHeight;
+ },
+ colWidthArr() {
+ let len = this.cellNum;
+ let colWidthArr = [];
+ if (this.fixedWrapperWidth) {
+ let width = this.outerWidth;
+ let num = this.cellNum;
+ if (this.showIndex) {
+ colWidthArr.push(this.indexWidth);
+ width -= this.indexWidth;
+ num -= 1;
+ }
+ let i = -1;
+ let itemColWidth = width / num;
+ while (++i < num) {
+ colWidthArr.push(itemColWidth);
+ }
+ } else {
+ let i = 0;
+ let hasWidthCellCount = 0; // 统计设置了width的列的数量,从而为没有设置width的列分配宽度
+ let noWidthCellIndexArr = []; // 没有设置宽度的列的序列
+ let hasWidthCellTotalWidth = 0; // 设置了width的列一共多宽
+ while (i < len) {
+ if (this.columnsHandled[i].width) {
+ hasWidthCellCount++;
+ hasWidthCellTotalWidth += this.columnsHandled[i].width;
+ colWidthArr.push(this.columnsHandled[i].width);
+ } else {
+ noWidthCellIndexArr.push(i);
+ colWidthArr.push(0);
+ }
+ i++;
+ }
+ let noWidthCellWidth = (this.tableWidth - hasWidthCellTotalWidth) / (len - hasWidthCellCount);
+ let w = 0;
+ let indexArrLen = noWidthCellIndexArr.length;
+ while (w < indexArrLen) {
+ colWidthArr[noWidthCellIndexArr[w]] = noWidthCellWidth;
+ w++;
+ }
+ // this.widthArr = colWidthArr;
+ }
+ return colWidthArr;
+ },
+ cursorOnHeader() {
+ return this.headerTrStyle.cursor ? this.headerTrStyle.cursor : ((this.isOnCellEdge || this.canResizeCell) ? 'col-resize' : 'default');
+ }
+ },
+ watch: {
+ highlightRow() {
+ this._clearCurrentRow();
+ }
+ },
+ methods: {
+ _tableResize() {
+ this.$nextTick(() => {
+ this.updateHeight();
+ this.setComputedProps();
+ let scrollBarWidth = this.totalRowHeight > this.wrapperHeight ? getScrollbarWidth() : 0;
+ this.outerWidth = this.$refs.outer.offsetWidth - 2 - scrollBarWidth;
+ let width = this.colWidth * this.columns.length + (this.showIndex ? this.indexWidthInside : 0);
+ // this.tableWidth = width > this.outerWidth ? width : this.outerWidth;
+ this.tableWidth = this.fixedWrapperWidth ? this.outerWidth : (width > this.outerWidth ? width : this.outerWidth);
+ if (width < this.outerWidth) this._setColWidthArr();
+ this.widthArr = this.colWidthArr;
+ });
+ },
+ updateHeight() {
+ this.$nextTick(() => {
+ let wrapperHeight = this.$refs.outer.offsetHeight;
+ this.itemNum = Math.ceil((wrapperHeight - this.headerHeight) / this.itemRowHeight) + this.appendNum;
+ this.moduleHeight = this.itemNum * this.itemRowHeight;
+ this.wrapperHeight = wrapperHeight;
+ this.setTopPlace();
+ });
+ },
+ setComputedProps() {
+ const len = this.insideTableData.length;
+ this.totalRowHeight = len * this.itemRowHeight;
+ },
+ setIndexWidth(len) {
+ let width = 70;
+ if (len <= 99) {
+ width = 50;
+ } else if (len > 99 && len <= 1000) {
+ width = 60;
+ } else if (len > 1000 && len <= 10000) {
+ width = 70;
+ } else if (len > 10000 && len <= 100000) {
+ width = 90;
+ } else {
+ width = 100;
+ }
+ return width;
+ },
+ setTopPlace() {
+ let scrollTop = this.scrollTop;
+ let t0 = 0;
+ let t1 = 0;
+ let t2 = 0;
+ if (scrollTop > this.moduleHeight) {
+ switch (this.currentIndex) {
+ case 0:
+ t0 = parseInt(scrollTop / (this.moduleHeight * 3));
+ t1 = t2 = t0;
+ break;
+ case 1:
+ t1 = parseInt((scrollTop - this.moduleHeight) / (this.moduleHeight * 3));
+ t0 = t1 + 1;
+ t2 = t1;
+ break;
+ case 2:
+ t2 = parseInt((scrollTop - this.moduleHeight * 2) / (this.moduleHeight * 3));
+ t0 = t1 = t2 + 1;
+ }
+ }
+ this.times0 = t0;
+ this.times1 = t1;
+ this.times2 = t2;
+ this.topPlaceholderHeight = parseInt(scrollTop / this.moduleHeight) * this.moduleHeight;
+ this.setTableData();
+ },
+ _initMountedHandle() {
+ if (this.indexWidth === undefined) this.indexWidthInside = this.setIndexWidth(this.insideTableData.length);
+ else this.indexWidthInside = this.indexWidth;
+ this.oldTableWidth = this.colWidthArr.reduce((sum, b) => {
+ return sum + b;
+ }, 0);
+ this.widthArr = this.colWidthArr;
+ if ((this.colWidth * this.columns.length + (this.showIndex ? this.indexWidthInside : 0)) < this.outerWidth) this._setColWidthArr();
+ },
+ _setColWidthArr() {
+ let widthArr = this.widthArr.map(width => {
+ return width / this.oldTableWidth * this.tableWidth;
+ });
+ this.oldTableWidth = this.tableWidth;
+ this.widthArr = widthArr;
+ },
+ _clearCurrentRow() {
+ this.highlightRowIndex = -1;
+ },
+ refreshHeader() {
+ this.updateID++;
+ },
+ _setHighlightRow(row) {
+ this.highlightRowIndex = row;
+ }
+ }
+};
diff --git a/frontend/src/components/vue-bigdata-table/util/index.js b/frontend/src/components/vue-bigdata-table/util/index.js
new file mode 100644
index 00000000..d235b557
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/util/index.js
@@ -0,0 +1,136 @@
+export const findNodeUpper = (ele, tag) => {
+ if (ele.parentNode) {
+ if (ele.parentNode.tagName === tag.toUpperCase()) {
+ return ele.parentNode;
+ } else {
+ if (ele.parentNode) return findNodeUpper(ele.parentNode, tag);
+ else return false;
+ }
+ }
+};
+
+export const getScrollbarWidth = () => {
+ let oP = document.createElement('p');
+ let styles = {
+ width: '100px',
+ height: '100px',
+ overflowY: 'scroll'
+ };
+ for (let i in styles) {
+ oP.style[i] = styles[i];
+ }
+ document.body.appendChild(oP);
+ let scrollbarWidth = oP.offsetWidth - oP.clientWidth;
+ oP.remove();
+ return scrollbarWidth;
+};
+
+export const createNewArray = (length, content = undefined) => {
+ let i = -1;
+ let arr = [];
+ while (++i < length) {
+ let con = Array.isArray(content) ? content[i] : content;
+ arr.push(con);
+ }
+ return arr;
+};
+
+export const iteratorByTimes = (times, fn) => {
+ let i = -1;
+ while (++i < times) {
+ fn(i);
+ }
+};
+
+export const getHeaderWords = (length) => {
+ let wordsArr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
+ let headerArr = [];
+ if (length <= 26) {
+ headerArr = wordsArr.slice(0, length);
+ } else {
+ headerArr = [...wordsArr];
+ let num = length - 26;
+ let firstWordIndex = 0;
+ let secondWordIndex = 0;
+ let i = -1;
+ while (++i < num) {
+ firstWordIndex = Math.floor(i / 26);
+ secondWordIndex = i % 26;
+ let sumWord = `${wordsArr[firstWordIndex]}${wordsArr[secondWordIndex]}`;
+ headerArr.push(sumWord);
+ }
+ }
+ return headerArr;
+};
+
+// 获取数组中第一个不为空的值
+export const getFirstNotNullValue = (array, index) => {
+ if (!(array && array.length)) return false;
+ let r = -1;
+ let rowLength = array.length;
+ while (++r < rowLength) {
+ let item = array[r][index];
+ if (item || item === 0) return item;
+ }
+ return false;
+};
+
+export const sortArr = (arr, index) => {
+ const isChineseReg = new RegExp('[\\u4E00-\\u9FFF]+', 'g');
+ if (arr.length <= 1) return;
+ const firstNotNullValue = getFirstNotNullValue(arr, index);
+ if (!firstNotNullValue && firstNotNullValue !== 0) return;
+ if (!isChineseReg.test(firstNotNullValue)) {
+ if (isNaN(Number(firstNotNullValue))) {
+ // 非中文非数值
+ arr.sort();
+ } else {
+ // 数值型
+ arr.sort((a, b) => {
+ return a[index] - b[index];
+ });
+ }
+ } else {
+ arr.sort((a, b) => {
+ return a[index].localeCompare(b[index], 'zh');
+ });
+ }
+};
+
+// 倒序
+export const sortDesArr = (arr, index) => {
+ const isChineseReg = new RegExp('[\\u4E00-\\u9FFF]+', 'g');
+ if (arr.length <= 1) return;
+ const firstNotNullValue = getFirstNotNullValue(arr, index);
+ if (!firstNotNullValue && firstNotNullValue !== 0) return;
+ if (!isChineseReg.test(firstNotNullValue)) {
+ if (isNaN(Number(firstNotNullValue))) {
+ // 非中文非数值
+ arr.sort().reverse();
+ } else {
+ // 数值型
+ arr.sort((a, b) => {
+ return b[index] - a[index];
+ });
+ }
+ } else {
+ arr.sort((a, b) => {
+ return b[index].localeCompare(a[index], 'zh');
+ });
+ }
+};
+
+export const hasOneOf = (str, targetArr) => {
+ let len = targetArr.length;
+ let i = -1;
+ while (++i < len) {
+ if (str.indexOf(targetArr[i]) >= 0) {
+ return true;
+ }
+ }
+ return false;
+};
+
+export const oneOf = (ele, targetArr) => {
+ return targetArr.indexOf(ele) > -1;
+};
diff --git a/frontend/src/components/vue-bigdata-table/vue-bigdata-table.less b/frontend/src/components/vue-bigdata-table/vue-bigdata-table.less
new file mode 100755
index 00000000..4dbe6a15
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/vue-bigdata-table.less
@@ -0,0 +1,311 @@
+@prefix: ~"vue-bigdata-table";
+@select-border-color: #3695FE;
+
+@keyframes scroll-tip {
+ 0% {
+ background: #fff;
+ }
+
+ 50% {
+ background: #d0e8ff;
+ }
+}
+
+.@{prefix} {
+ width: 100%;
+ box-sizing: border-box;
+
+ * {
+ font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
+ color: #495060;
+ font-size: 12px;
+ font-weight: 400;
+ }
+
+ &-outer {
+ width: 100%;
+ height: 100%;
+ overflow: auto;
+ border: 1px solid #e9eaec;
+ box-sizing: border-box;
+ position: relative;
+
+ .@{prefix}-header-wrapper {
+ box-sizing: border-box;
+ z-index: 70;
+
+ &.header-wrapper-fixed {
+ position: -webkit-sticky;
+ position: sticky;
+ }
+
+ table {
+ table-layout: fixed;
+ height: 100%;
+
+ tr th {
+ border-right: 1px solid #e9eaec;
+ border-bottom: 1px solid #e9eaec;
+ background: #fff;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ word-break: break-all;
+
+ // &:last-child{
+ // border-right: none;
+ // }
+ .@{prefix}-header-inside-wrapper {
+ box-sizing: border-box;
+ padding: 0 8px;
+ }
+ }
+ }
+ }
+ }
+
+ &-fixed-header {
+ position: -webkit-sticky;
+ position: sticky;
+ transform: translateX(0);
+ left: 0;
+ z-index: 110;
+ transition: box-shadow .2s ease;
+
+ &.box-shadow {
+ box-shadow: 2px 0 6px -2px rgba(0, 0, 0, .2);
+ transition: box-shadow .2s ease;
+ }
+ }
+
+ &-wrapper {
+ width: 100%;
+ border-bottom: none;
+
+ .@{prefix}-content {
+ width: 100%;
+ height: auto;
+ // &.noselect-text{
+ // -webkit-touch-callout: none;
+ // -webkit-user-select: none;
+ // -khtml-user-select: none;
+ // -moz-user-select: none;
+ // -ms-user-select: none;
+ // user-select: none;
+ // }
+ }
+
+ &:nth-child(2) {
+ border-top: 1px solid #e9eaec;
+ }
+
+ &:nth-child(4) {
+ border-bottom: 1px solid #e9eaec;
+ }
+
+ .@{prefix}-data-table {
+ &.@{prefix}-content-table {
+
+ left: 0;
+ top: 0;
+ }
+
+ border-bottom: none;
+ border-top: none;
+ table-layout: fixed;
+
+ tr {
+ background: #fff;
+
+ &.scroll-to-row-tip {
+ animation: scroll-tip .6s 3;
+ }
+
+ td {
+ min-width: 0;
+ height: 48px;
+ box-sizing: border-box;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ border-bottom: 1px solid #e9eaec;
+ border-right: 1px solid #e9eaec;
+
+ border-left: 1px solid transparent;
+ border-top: 1px solid transparent; // 表格选中
+
+ .@{prefix}-cell {
+ box-sizing: border-box;
+ padding: 0 18px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ word-break: break-all;
+ }
+
+ // &:last-child{
+ // border-right: none;
+ // }
+ .edit-item-con {
+ width: 100%;
+ text-align: left;
+ padding: 0 6px;
+ box-sizing: border-box;
+
+ .edit-item {
+ &-input {
+ width: ~"calc(100% - 50px)";
+ float: left;
+ }
+
+ &-btn-con {
+ float: left;
+
+ .edit-btn {
+ width: 20px;
+ margin: 7px 4px 0 0;
+ }
+ }
+ }
+ }
+
+ &.start-select-cell {
+ border-left: 1px solid @select-border-color;
+ border-top: 1px solid @select-border-color;
+ }
+
+ &.end-select-cell {
+ border-right: 1px solid @select-border-color;
+ border-bottom: 1px solid @select-border-color;
+ }
+
+ &.right-top-select-cell {
+ border-right: 1px solid @select-border-color;
+ border-top: 1px solid @select-border-color;
+ }
+
+ &.left-bottom-select-cell {
+ border-left: 1px solid @select-border-color;
+ border-bottom: 1px solid @select-border-color;
+ }
+
+ &.top-center-select-cell {
+ border-top: 1px solid @select-border-color;
+ }
+
+ &.bottom-center-select-cell {
+ border-bottom: 1px solid @select-border-color;
+ }
+
+ &.left-center-select-cell {
+ border-left: 1px solid @select-border-color;
+ }
+
+ &.right-center-select-cell {
+ border-right: 1px solid @select-border-color;
+ }
+ }
+
+ &.stripe-gray {
+ background: #f8f8f9;
+ }
+
+ &.highlight-row {
+ background: #ebf7ff;
+ }
+ }
+
+ &-left {
+ text-align: left;
+ }
+
+ &-center {
+ text-align: center;
+ }
+
+ &-right {
+ text-align: right;
+ }
+ }
+ }
+
+ &-fixed {
+ .@{prefix}-header-wrapper {
+ top: 0;
+ left: 0;
+ box-sizing: border-box;
+ }
+ }
+
+ &-fixed-table {
+ position: -webkit-sticky;
+ position: sticky;
+ left: 0;
+ z-index: 60;
+ transition: box-shadow .2s ease;
+
+ &.box-shadow {
+ box-shadow: 2px 0 6px -2px rgba(0, 0, 0, .2);
+ transition: box-shadow .2s ease;
+ }
+
+ td {
+ border-right: 1px solid #e9eaec;
+ // &:last-child{
+ // border-right: 1px solid #e9eaec !important;
+ // }
+ }
+ }
+
+ &-item-table {
+ position: relative;
+ }
+
+ .sort-button {
+ &-wrapper {
+ display: inline-block;
+ position: relative;
+ width: 10px;
+ height: 11px;
+ transform: translateY(1px);
+ }
+
+ &-item {
+ position: absolute;
+ display: inline-block;
+ width: 0;
+ height: 0;
+ border: 4px solid transparent;
+ margin: 0;
+ padding: 0;
+ cursor: pointer;
+ transition: border-color .2s ease;
+
+ &-up {
+ top: -4px;
+ border-bottom: 4px solid #bbbec4;
+
+ &:hover {
+ border-bottom: 4px solid #495060;
+ }
+
+ &-active {
+ border-bottom: 4px solid #2d8cf0;
+ }
+ }
+
+ &-down {
+ bottom: -4px;
+ border-top: 4px solid #bbbec4;
+
+ &:hover {
+ border-top: 4px solid #495060;
+ }
+
+ &-active {
+ border-top: 4px solid #2d8cf0;
+ }
+ }
+ }
+ }
+}
diff --git a/frontend/src/components/vue-bigdata-table/vue-bigdata-table.vue b/frontend/src/components/vue-bigdata-table/vue-bigdata-table.vue
new file mode 100644
index 00000000..65bd8c1e
--- /dev/null
+++ b/frontend/src/components/vue-bigdata-table/vue-bigdata-table.vue
@@ -0,0 +1,441 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ col.title }}
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+ {{ col.title }}
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/views/virtual/orders/cards.vue b/frontend/src/views/virtual/orders/cards.vue
index ec2db8ba..65aa8957 100644
--- a/frontend/src/views/virtual/orders/cards.vue
+++ b/frontend/src/views/virtual/orders/cards.vue
@@ -127,15 +127,14 @@
-
+ :height="449"
+ >
@@ -148,3 +147,14 @@
+
+
+
diff --git a/frontend/src/views/virtual/orders/js/cards.js b/frontend/src/views/virtual/orders/js/cards.js
index ce8f62d9..74499809 100644
--- a/frontend/src/views/virtual/orders/js/cards.js
+++ b/frontend/src/views/virtual/orders/js/cards.js
@@ -1,4 +1,7 @@
export default {
+ components: {
+ BTable: resolve => require(['components/table'], resolve)
+ },
props: {
show: {
type: Boolean,
@@ -20,13 +23,17 @@ export default {
show: true
},
params: {
- company_id: "",
- package_id: "",
- carrier_operator: "",
- time: [],
- used: 0,
- sim: ""
+ company_id: '',
+ package_id: '',
+ carrier_operator: '',
+ time: [
+ this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM-DD'),
+ this.moment().subtract('2', 'months').endOf('month').format('YYYY-MM-DD')
+ ],
+ used: '',
+ sim: ''
},
+ showCards: [],
orderColumns: [
{
width: 60,
@@ -96,52 +103,52 @@ export default {
{
title: "订单编号",
key: "sn",
- width: 200
+ width: 165
},
{
title: "企业名称",
key: "company_name",
- width: 280
+ width: 210
},
{
title: "运营商",
key: "carrier_operator_name",
- width: 90
+ width: 75
},
{
title: "套餐名称",
key: "package_name",
- width: 180
+ width: 150
},
{
title: "支付方式",
key: "pay_channel_name",
- width: 100
+ width: 90
},
{
title: "订单卡量",
key: "counts",
- width: 100
+ width: 90
},
{
title: "订单金额",
key: "total_price",
- width: 120
+ width: 100
},
{
title: "订单时间",
key: "order_at",
- width: 170
+ width: 150
},
{
title: "所需卡量",
key: "",
- width: 100
+ width: 90
}
],
- cardColumns: [
+ cardColumns2: [
{
width: 60,
align: "center",
@@ -201,6 +208,11 @@ export default {
});
}
},
+ {
+ title: "序号",
+ key: "_index",
+ width: 140
+ },
{
title: "SIM",
key: "sim",
@@ -231,6 +243,87 @@ export default {
key: "package_name",
width: 200
}
+ ],
+
+ cardColumns: [
+ {
+ width: 60,
+ align: 'center',
+ render: (h) => {
+ let value = false;
+ let indeterminate = false;
+
+ let select = this.selected.find(item => {
+ return item.id === this.order_id;
+ });
+
+ value = !!select;
+
+ indeterminate =
+ select &&
+ select.cards &&
+ select.cards.length !== this.cards.length;
+
+ return h("Checkbox", {
+ props: {
+ indeterminate: value && indeterminate,
+ value: value
+ },
+ on: {
+ input: value => {
+ console.log(value);
+ }
+ }
+ });
+ },
+ cellRender: (h, context) => {
+ let value = !!context.value;
+
+ return h("Checkbox", {
+ props: {
+ value: value
+ },
+ on: {
+ input: value => {
+ console.log(value);
+ }
+ }
+ });
+ }
+ },
+ {
+ title: "SIM",
+ width: 135,
+ align: 'center'
+ },
+ {
+ title: "状态",
+ width: 100,
+ align: 'center',
+ cellRender: (h, context) => {
+ return h(
+ "Tag", {
+ props: {
+ color: context.value ? "error" : "primary"
+ }
+ },
+ context.value ? "已使用" : "未使用"
+ );
+ }
+ },
+ {
+ title: "数量",
+ width: 80,
+ align: 'center'
+ },
+ {
+ title: "VD企业",
+ width: 210
+ },
+ {
+ title: "VD套餐",
+ width: 150
+ }
]
};
},
@@ -297,6 +390,17 @@ export default {
this.$store
.dispatch("getCards", params)
.then(cards => {
+ this.showCards = cards.map(item => {
+ return [
+ false,
+ item.sim,
+ item.virtual_order_id ? 1 : 0,
+ item.counts,
+ item.virtual ? item.virtual.company_name : '',
+ item.virtual ? item.virtual.package_name : ''
+ ];
+ });
+
this.cardLoading = false;
resolve(cards);
})
@@ -316,12 +420,13 @@ export default {
},
resetSearch() {
for (let k in this.params) {
- if (k === "time") {
- this.params[k] = [];
- } else if (k === "used") {
- this.params[k] = 0;
+ if (k === 'time') {
+ this.params[k] = [
+ this.moment().subtract('2', 'months').startOf('month').format('YYYY-MM-DD'),
+ this.moment().subtract('2', 'months').endOf('month').format('YYYY-MM-DD')
+ ];
} else {
- this.params[k] = "";
+ this.params[k] = '';
}
}
this.index(1);
@@ -335,15 +440,20 @@ export default {
cards: cards
};
- this.cards = this.cards.map(item => {
- item._checked = true;
+ this.showCards = this.showCards.map(item => {
+ item[0] = true;
return item;
});
- this.$store.commit("PUSH_REAL_ORDER_SELECTED", obj);
+ this.$store.commit('PUSH_REAL_ORDER_SELECTED', obj);
});
} else {
- this.$store.commit("REMOVE_REAL_ORDER_SELECTED", row.id);
+ this.showCards = this.showCards.map(item => {
+ item[0] = false;
+ return item;
+ });
+
+ this.$store.commit('REMOVE_REAL_ORDER_SELECTED', row.id);
}
},
handleSelectCards(t, a, b) {
diff --git a/frontend/src/views/virtual/orders/js/edit.js b/frontend/src/views/virtual/orders/js/edit.js
index 93ea231c..b6c60bdf 100644
--- a/frontend/src/views/virtual/orders/js/edit.js
+++ b/frontend/src/views/virtual/orders/js/edit.js
@@ -144,6 +144,9 @@ export default {
this.params[k] = '';
}
+ this.params.unit_price = 0;
+ this.params.counts = 0;
+ this.params.area = [];
this.my_show = false;
},
handleChange(type) {
diff --git a/frontend/vue.config.js b/frontend/vue.config.js
index 09efd1a2..f840ae7e 100644
--- a/frontend/vue.config.js
+++ b/frontend/vue.config.js
@@ -10,6 +10,7 @@ module.exports = {
lintOnSave: true,
chainWebpack: config => {
config.resolve.alias
+ .set('node_modules', resolve('node_modules'))
.set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components'))
.set('src', resolve('src'))
.set('views', resolve('src/views'))
diff --git a/tests/SchemaTest.php b/tests/SchemaTest.php
index 80ab7075..464b7e70 100644
--- a/tests/SchemaTest.php
+++ b/tests/SchemaTest.php
@@ -1,13 +1,20 @@
truncate();
-Schema::create('real_order_cards_table_partition', function (Blueprint $table) {
+DB::table('virtual_order_cards_partition')->truncate();
+
+dd();
+
+Schema::dropIfExists('real_order_cards_partition');
+
+Schema::create('real_order_cards_partition', function (Blueprint $table) {
$table->increments('id')->comment('关联表ID');
$table->tinyInteger('type')->unsigned()->default(0)->comment('订单类型(1:套餐续费 2:续费包 3:加油包 4:可选包 5:附加包)');
$table->bigInteger('sim')->unsigned()->default(0)->comment('sim号');