This commit is contained in:
aoli.qu 2021-08-19 09:01:06 +08:00
parent cfa8c52c92
commit 4884f098c8
161 changed files with 8225 additions and 880 deletions

2
.env
View File

@ -1,3 +1,3 @@
NODE_ENV=production NODE_ENV=production
VUE_APP_PREVIEW=false VUE_APP_PREVIEW=false
VUE_APP_API_BASE_URL=/api VUE_APP_API_BASE_URL=/dawa

View File

@ -1,3 +1,3 @@
NODE_ENV=development NODE_ENV=development
VUE_APP_PREVIEW=true VUE_APP_PREVIEW=true
VUE_APP_API_BASE_URL=/api VUE_APP_API_BASE_URL=/dawa

View File

@ -1,3 +1,3 @@
NODE_ENV=production NODE_ENV=production
VUE_APP_PREVIEW=true VUE_APP_PREVIEW=true
VUE_APP_API_BASE_URL=/api VUE_APP_API_BASE_URL=/dawa

190
package-lock.json generated
View File

@ -3073,6 +3073,15 @@
"integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==", "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==",
"dev": true "dev": true
}, },
"adler-32": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz",
"integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"ajv": { "ajv": {
"version": "6.12.6", "version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -3953,6 +3962,11 @@
"file-uri-to-path": "1.0.0" "file-uri-to-path": "1.0.0"
} }
}, },
"blob.js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/blob.js/-/blob.js-1.0.1.tgz",
"integrity": "sha1-VHtEmyUshVMT6De1PRW0HQAOodI="
},
"bluebird": { "bluebird": {
"version": "3.7.2", "version": "3.7.2",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@ -4446,6 +4460,16 @@
"lazy-cache": "^1.0.3" "lazy-cache": "^1.0.3"
} }
}, },
"cfb": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.0.tgz",
"integrity": "sha512-sXMvHsKCICVR3Naq+J556K+ExBo9n50iKl6LGarlnvuA2035uMlGA/qVrc0wQtow5P1vJEw9UyrKLCbtIKz+TQ==",
"requires": {
"adler-32": "~1.2.0",
"crc-32": "~1.2.0",
"printj": "~1.1.2"
}
},
"chalk": { "chalk": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
@ -4855,6 +4879,22 @@
} }
} }
}, },
"codepage": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz",
"integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=",
"requires": {
"commander": "~2.14.1",
"exit-on-epipe": "~1.0.1"
},
"dependencies": {
"commander": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
"integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw=="
}
}
},
"collection-visit": { "collection-visit": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@ -5329,8 +5369,7 @@
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
"dev": true
}, },
"cosmiconfig": { "cosmiconfig": {
"version": "5.2.1", "version": "5.2.1",
@ -5356,6 +5395,15 @@
} }
} }
}, },
"crc-32": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz",
"integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==",
"requires": {
"exit-on-epipe": "~1.0.1",
"printj": "~1.1.0"
}
},
"create-ecdh": { "create-ecdh": {
"version": "4.0.4", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
@ -7439,6 +7487,11 @@
"integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
"dev": true "dev": true
}, },
"exit-on-epipe": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz",
"integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw=="
},
"expand-brackets": { "expand-brackets": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
@ -7814,6 +7867,11 @@
"schema-utils": "^2.5.0" "schema-utils": "^2.5.0"
} }
}, },
"file-saver": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
},
"file-uri-to-path": { "file-uri-to-path": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@ -8015,6 +8073,11 @@
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"dev": true "dev": true
}, },
"frac": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA=="
},
"fragment-cache": { "fragment-cache": {
"version": "0.2.1", "version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
@ -8780,6 +8843,11 @@
"dev": true, "dev": true,
"optional": true "optional": true
}, },
"immediate": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
},
"import-cwd": { "import-cwd": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@ -10932,6 +11000,24 @@
"nopt": "^5.0.0" "nopt": "^5.0.0"
} }
}, },
"js-export-excel": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/js-export-excel/-/js-export-excel-1.1.4.tgz",
"integrity": "sha512-19m7e3Gnn4CRfHXoFrLYj4fFfJ/KpvI7HRRn25p4GXYD+AlTV+1oU24NH6S904Ksi44tSx7futxhouOPAQ22oQ==",
"requires": {
"blob.js": "^1.0.1",
"file-saver": "^1.3.3",
"script-loader": "0.7.2",
"xlsx": "0.16.3"
},
"dependencies": {
"file-saver": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.8.tgz",
"integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg=="
}
}
},
"js-message": { "js-message": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz",
@ -11104,6 +11190,17 @@
"verror": "1.10.0" "verror": "1.10.0"
} }
}, },
"jszip": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz",
"integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==",
"requires": {
"lie": "~3.3.0",
"pako": "~1.0.2",
"readable-stream": "~2.3.6",
"set-immediate-shim": "~1.0.1"
}
},
"killable": { "killable": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@ -11263,6 +11360,14 @@
"type-check": "~0.3.2" "type-check": "~0.3.2"
} }
}, },
"lie": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
"requires": {
"immediate": "~3.0.5"
}
},
"lines-and-columns": { "lines-and-columns": {
"version": "1.1.6", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
@ -12702,8 +12807,7 @@
"pako": { "pako": {
"version": "1.0.11", "version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
"dev": true
}, },
"parallel-transform": { "parallel-transform": {
"version": "1.2.0", "version": "1.2.0",
@ -13742,6 +13846,11 @@
} }
} }
}, },
"printj": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz",
"integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ=="
},
"process": { "process": {
"version": "0.11.10", "version": "0.11.10",
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
@ -13751,8 +13860,7 @@
"process-nextick-args": { "process-nextick-args": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
"dev": true
}, },
"progress": { "progress": {
"version": "2.0.3", "version": "2.0.3",
@ -13992,6 +14100,11 @@
} }
} }
}, },
"raw-loader": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz",
"integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao="
},
"react-is": { "react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -14071,7 +14184,6 @@
"version": "2.3.7", "version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dev": true,
"requires": { "requires": {
"core-util-is": "~1.0.0", "core-util-is": "~1.0.0",
"inherits": "~2.0.3", "inherits": "~2.0.3",
@ -14085,8 +14197,7 @@
"isarray": { "isarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
"dev": true
} }
} }
}, },
@ -14539,8 +14650,7 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
"dev": true
}, },
"safe-regex": { "safe-regex": {
"version": "1.1.0", "version": "1.1.0",
@ -14620,6 +14730,14 @@
"ajv-keywords": "^3.5.2" "ajv-keywords": "^3.5.2"
} }
}, },
"script-loader": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/script-loader/-/script-loader-0.7.2.tgz",
"integrity": "sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA==",
"requires": {
"raw-loader": "~0.5.1"
}
},
"select": { "select": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
@ -14775,6 +14893,11 @@
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true "dev": true
}, },
"set-immediate-shim": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
},
"set-value": { "set-value": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
@ -15277,6 +15400,14 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true "dev": true
}, },
"ssf": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
"requires": {
"frac": "~1.1.2"
}
},
"sshpk": { "sshpk": {
"version": "1.16.1", "version": "1.16.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
@ -15507,7 +15638,6 @@
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": { "requires": {
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
@ -16474,8 +16604,7 @@
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
"dev": true
}, },
"util.promisify": { "util.promisify": {
"version": "1.1.1", "version": "1.1.1",
@ -17752,11 +17881,21 @@
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
}, },
"wmf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw=="
},
"wolfy87-eventemitter": { "wolfy87-eventemitter": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz",
"integrity": "sha1-NcGsDdGsDBXjXZgVCPwiCEoToBE=" "integrity": "sha1-NcGsDdGsDBXjXZgVCPwiCEoToBE="
}, },
"word": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA=="
},
"word-wrap": { "word-wrap": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
@ -17871,6 +18010,29 @@
"async-limiter": "~1.0.0" "async-limiter": "~1.0.0"
} }
}, },
"xlsx": {
"version": "0.16.3",
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.16.3.tgz",
"integrity": "sha512-LInZ1OK6vpe+Em8XDZ5gDH3WixARwxI7UWc+3chLeafI6gUwECEgL43k4Tjbs1uRfkxpM7wQFy5DLE0hFBRqRw==",
"requires": {
"adler-32": "~1.2.0",
"cfb": "^1.1.4",
"codepage": "~1.14.0",
"commander": "~2.17.1",
"crc-32": "~1.2.0",
"exit-on-epipe": "~1.0.1",
"ssf": "~0.11.2",
"wmf": "~1.0.1",
"word": "~0.3.0"
},
"dependencies": {
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
}
}
},
"xml-name-validator": { "xml-name-validator": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",

View File

@ -17,6 +17,9 @@
"axios": "^0.19.0", "axios": "^0.19.0",
"core-js": "^3.1.2", "core-js": "^3.1.2",
"enquire.js": "^2.1.6", "enquire.js": "^2.1.6",
"file-saver": "^2.0.5",
"js-export-excel": "^1.1.4",
"jszip": "^3.7.1",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
"lodash.get": "^4.4.2", "lodash.get": "^4.4.2",
"lodash.pick": "^4.4.0", "lodash.pick": "^4.4.0",

View File

@ -20,7 +20,6 @@ export default {
// //
const { title } = this.$route.meta const { title } = this.$route.meta
title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`)) title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`))
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
} }
} }

60
src/api/bms/brand.js Normal file
View File

@ -0,0 +1,60 @@
import request from '@/utils/request'
const brandApi = {
add: '/bms/brand/add',
get: '/bms/brand/get',
update: '/bms/brand/update',
del: '/bms/brand/delete',
page: '/bms/brand/page',
list: '/bms/brand/listByCategory',
updateStatus: '/bms/brand/updateStatus'
}
export function brandAdd (params) {
return request({
url: brandApi.add,
method: 'post',
data: params
})
}
export function brandGet (params) {
return request({
url: brandApi.get,
method: 'post',
data: params
})
}
export function brandUpdate (params) {
return request({
url: brandApi.update,
method: 'post',
data: params
})
}
export function brandDelete (params) {
return request({
url: brandApi.del,
method: 'post',
data: params
})
}
export function brandPage (params) {
return request({
url: brandApi.page,
method: 'post',
data: params
})
}
export function brandList (params) {
return request({
url: brandApi.list,
method: 'post',
data: params
})
}
export function brandUpdateStatus (params) {
return request({
url: brandApi.updateStatus,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,45 @@
import request from '@/utils/request'
const businessModelApi = {
add: '/bms/businessModel/save',
get: '/bms/businessModel/get',
update: '/bms/businessModel/update',
del: '/bms/businessModel/delete',
page: '/bms/businessModel/page',
list: '/bms/businessModel/list'
}
export function add (params) {
return request({
url: businessModelApi.add,
method: 'post',
data: params
})
}
export function get (params) {
return request({
url: businessModelApi.get,
method: 'post',
data: params
})
}
export function update (params) {
return request({
url: businessModelApi.update,
method: 'post',
data: params
})
}
export function del (params) {
return request({
url: businessModelApi.del,
method: 'post',
data: params
})
}
export function list (params) {
return request({
url: businessModelApi.list,
method: 'post',
data: params
})
}

44
src/api/bms/catalog.js Normal file
View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
const catalogApi = {
add: '/bms/catalog/add',
update: '/bms/catalog/update',
del: '/bms/catalog/delete',
page: '/bms/catalog/page',
get: '/bms/catalog/get'
}
export function catalogAdd (params) {
return request({
url: catalogApi.add,
method: 'post',
data: params
})
}
export function catalogUpdate (params) {
return request({
url: catalogApi.update,
method: 'post',
data: params
})
}
export function catalogDel (params) {
return request({
url: catalogApi.del,
method: 'post',
data: params
})
}
export function catalogPage (params) {
return request({
url: catalogApi.page,
method: 'post',
data: params
})
}
export function catalogGet (params) {
return request({
url: catalogApi.get,
method: 'post',
data: params
})
}

60
src/api/bms/category.js Normal file
View File

@ -0,0 +1,60 @@
import request from '@/utils/request'
const api = {
listStoreCategory: '/bms/category/listStoreCategory',
add: '/bms/category/add',
update: '/bms/category/update',
delete: '/bms/category/delete',
page: '/bms/category/pageCategory',
get: '/bms/category/get',
updateStatus: '/bms/category/updateStatus'
}
export function listStoreCategory (params) {
return request({
url: api.listStoreCategory,
method: 'post',
data: params
})
}
export function addCategory (params) {
return request({
url: api.add,
method: 'post',
data: params
})
}
export function updateCategory (params) {
return request({
url: api.update,
method: 'post',
data: params
})
}
export function deleteCategory (params) {
return request({
url: api.delete,
method: 'post',
data: params
})
}
export function pageCategory (params) {
return request({
url: api.page,
method: 'post',
data: params
})
}
export function getCategory (params) {
return request({
url: api.get,
method: 'post',
data: params
})
}
export function updateStatusCategory (params) {
return request({
url: api.updateStatus,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,60 @@
import request from '@/utils/request'
const CorporationApi = {
add: '/bms/corporation/add',
get: '/bms/corporation/get',
update: '/bms/corporation/update',
del: '/bms/corporation/delete',
page: '/bms/corporation/page',
list: '/bms/corporation/list',
updateStatus: '/bms/corporation/updateStatus'
}
export function corporationAdd (params) {
return request({
url: CorporationApi.add,
method: 'post',
data: params
})
}
export function corporationPage (params) {
return request({
url: CorporationApi.page,
method: 'post',
data: params
})
}
export function corporationUpdate (params) {
return request({
url: CorporationApi.update,
method: 'post',
data: params
})
}
export function corporationDelete (params) {
return request({
url: CorporationApi.del,
method: 'post',
data: params
})
}
export function corporationList (params) {
return request({
url: CorporationApi.list,
method: 'post',
data: params
})
}
export function corporationGet (params) {
return request({
url: CorporationApi.get,
method: 'post',
data: params
})
}
export function updateStatus (params) {
return request({
url: CorporationApi.updateStatus,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,11 @@
import request from '@/utils/request'
const deliverMethodApi = {
list: '/bms/deliverMethod/list'
}
export function listDeliverMethod (params) {
return request({
url: deliverMethodApi.list,
method: 'post',
data: params
})
}

44
src/api/bms/division.js Normal file
View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
const divisionApi = {
add: '/bms/division/save',
get: '/bms/division/get',
update: '/bms/division/update',
del: '/bms/division/delete',
listDivision: '/bms/division/listByParentCode'
}
export function divisionAdd (params) {
return request({
url: divisionApi.add,
method: 'post',
data: params
})
}
export function divisionGet (params) {
return request({
url: divisionApi.get,
method: 'post',
data: params
})
}
export function divisionUpdate (params) {
return request({
url: divisionApi.update,
method: 'post',
data: params
})
}
export function divisionDelete (params) {
return request({
url: divisionApi.del,
method: 'post',
data: params
})
}
export function listDivision (params) {
return request({
url: divisionApi.listDivision,
method: 'post',
data: params
})
}

78
src/api/bms/mall.js Normal file
View File

@ -0,0 +1,78 @@
import request from '@/utils/request'
const api = {
add: '/bms/mall/save',
get: '/bms/mall/get',
update: '/bms/mall/update',
del: '/bms/mall/delete',
page: '/bms/mall/page',
list: '/bms/mall/list',
updateStatus: '/bms/mall/updateStatus',
corporationList: '/bms/corporation/list',
listByUserType: '/bms/mall/listByUserType'
}
export function add (params) {
return request({
url: api.add,
method: 'post',
data: params
})
}
export function get (params) {
return request({
url: api.get,
method: 'post',
data: params
})
}
export function update (params) {
return request({
url: api.update,
method: 'post',
data: params
})
}
export function del (params) {
return request({
url: api.del,
method: 'post',
data: params
})
}
export function page (params) {
return request({
url: api.page,
method: 'post',
data: params
})
}
export function list (params) {
return request({
url: api.list,
method: 'post',
data: params
})
}
export function updateStatus (params) {
return request({
url: api.updateStatus,
method: 'post',
data: params
})
}
export function corporationList (params) {
return request({
url: api.corporationList,
method: 'post',
data: params
})
}
export function listByUserType (params) {
return request({
url: api.listByUserType,
method: 'post',
data: params
})
}

20
src/api/bms/org.js Normal file
View File

@ -0,0 +1,20 @@
import request from '@/utils/request'
const orgApi = {
orgTreeGet: '/bms/org/getOrgTree',
orgByUserType: '/bms/org/getByUserType'
}
export function orgTreeGet (params) {
return request({
url: orgApi.orgTreeGet,
method: 'post',
data: params
})
}
export function orgByUserType (params) {
return request({
url: orgApi.orgByUserType,
method: 'post',
data: params
})
}

52
src/api/bms/payMethod.js Normal file
View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
const payMethodApi = {
add: '/bms/storePayMethod/add',
get: '/bms/storePayMethod/getById',
update: '/bms/storePayMethod/update',
del: '/bms/storePayMethod/delete',
list: '/bms/storePayMethod/list',
page: '/bms/storePayMethod/page'
}
export function storePayMethodAdd (params) {
return request({
url: payMethodApi.add,
method: 'post',
data: params
})
}
export function storePayMethodPage (params) {
return request({
url: payMethodApi.page,
method: 'post',
data: params
})
}
export function storePayMethodGet (params) {
return request({
url: payMethodApi.get,
method: 'post',
data: params
})
}
export function storePayMethodUpdate (params) {
return request({
url: payMethodApi.update,
method: 'post',
data: params
})
}
export function storePayMethodDelete (params) {
return request({
url: payMethodApi.del,
method: 'post',
data: params
})
}
export function storePayMethodList (params) {
return request({
url: payMethodApi.list,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
const settlementAccountApi = {
add: '/bms/storeSettlementAccount/add',
get: '/bms/storeSettlementAccount/getById',
update: '/bms/storeSettlementAccount/update',
del: '/bms/storeSettlementAccount/delete',
list: '/bms/storeSettlementAccount/list',
page: '/bms/storeSettlementAccount/page'
}
export function settlementAccountAdd (params) {
return request({
url: settlementAccountApi.add,
method: 'post',
data: params
})
}
export function settlementAccountPage (params) {
return request({
url: settlementAccountApi.page,
method: 'post',
data: params
})
}
export function settlementAccountGet (params) {
return request({
url: settlementAccountApi.get,
method: 'post',
data: params
})
}
export function settlementAccountUpdate (params) {
return request({
url: settlementAccountApi.update,
method: 'post',
data: params
})
}
export function settlementAccountDelete (params) {
return request({
url: settlementAccountApi.del,
method: 'post',
data: params
})
}
export function settlementAccountList (params) {
return request({
url: settlementAccountApi.list,
method: 'post',
data: params
})
}

60
src/api/bms/store.js Normal file
View File

@ -0,0 +1,60 @@
import request from '@/utils/request'
const api = {
add: '/bms/store/add',
get: '/bms/store/get',
update: '/bms/store/update',
del: '/bms/store/delete',
page: '/bms/store/page',
list: '/bms/store/list',
updateStatus: '/bms/store/updateStatus'
}
export function storeAdd (params) {
return request({
url: api.add,
method: 'post',
data: params
})
}
export function storeGet (params) {
return request({
url: api.get,
method: 'post',
data: params
})
}
export function storeUpdate (params) {
return request({
url: api.update,
method: 'post',
data: params
})
}
export function storeDel (params) {
return request({
url: api.del,
method: 'post',
data: params
})
}
export function storePage (params) {
return request({
url: api.page,
method: 'post',
data: params
})
}
export function storeList (params) {
return request({
url: api.list,
method: 'post',
data: params
})
}
export function storeUpdateStatus (params) {
return request({
url: api.updateStatus,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,78 @@
import request from '@/utils/request'
const customerApi = {
page: '/customer/customer/pageByNameAndMobile',
del: '/customer/customer/delete',
add: '/customer/customer/add',
update: '/customer/customer/update',
get: '/customer/customer/getById',
updateStatus: '/customer/customer/updateStatus',
getCategoryList: '/customer/customerCategory/listCategoryByName',
listCustomer: '/customer/customer/listByNameAndMobile'
}
export function customerAdd (params) {
return request({
url: customerApi.add,
method: 'post',
data: params
})
}
export function customerGet (params) {
return request({
url: customerApi.get,
method: 'post',
data: params
})
}
export function customerUpdate (params) {
return request({
url: customerApi.update,
method: 'post',
data: params
})
}
export function customerDelete (params) {
return request({
url: customerApi.del,
method: 'post',
data: params
})
}
export function customerPage (params) {
return request({
url: customerApi.page,
method: 'post',
data: params
})
}
export function customerUpdateStatus (params) {
return request({
url: customerApi.updateStatus,
method: 'post',
data: params
})
}
export function categoryTypeList (params) {
return request({
url: customerApi.getCategoryList,
method: 'post',
data: params
})
}
export const genderMap = {
'MALE': '男',
'FEMALE': '女'
}
export const deliverTypeMap = {
'SELF': '自提',
'LOGISTICS': '发物流',
'DESIGNATED_PLACE': '送指定点',
'AUTO_CAR': '送车'
}
export function listCustomer (params) {
return request({
url: customerApi.listCustomer,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,12 @@
import request from '@/utils/request'
const dashboardApi = {
get: '/security/dashboard/data'
}
export function dashboardGet (params) {
return request({
url: dashboardApi.get,
method: 'post',
data: params
})
}

14
src/api/file/file.js Normal file
View File

@ -0,0 +1,14 @@
import { axios } from '@/utils/request'
const fileApi = {
add: '/file/file/add',
del: '/file/file/delete',
get: '/file/file/get',
upload: '/file/file/uploadFile'
}
export function fileUpload (formData) {
return axios.post(fileApi.upload, formData, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
}

100
src/api/gms/goods.js Normal file
View File

@ -0,0 +1,100 @@
import request from '@/utils/request'
const goodsApi = {
add: '/gms/goods/save',
get: '/gms/goods/getGoodsById',
update: '/gms/goods/update',
del: '/gms/goods/delete',
page: '/gms/goods/page',
list: '/gms/goods/list',
updateStatus: '/gms/goods/updateGoodsStatus',
checkGoodsCode: '/gms/goods/checkGoodsGoodsCodeUnique',
checkGoodsBarCode: '/gms/goods/checkGoodsGoodsBarCodeUnique',
goodsCount: '/gms/goods/countGoodsInfo',
detail: '/gms/goods/get',
listByStoreId: '/gms/goods/listByStoreId'
}
export function goodsAdd (params) {
return request({
url: goodsApi.add,
method: 'post',
data: params
})
}
export function goodsGet (params) {
return request({
url: goodsApi.get,
method: 'post',
data: params
})
}
export function goodsUpdate (params) {
return request({
url: goodsApi.update,
method: 'post',
data: params
})
}
export function goodsDelete (params) {
return request({
url: goodsApi.del,
method: 'post',
data: params
})
}
export function goodsPage (params) {
return request({
url: goodsApi.page,
method: 'post',
data: params
})
}
export function goodsList (params) {
return request({
url: goodsApi.list,
method: 'post',
data: params
})
}
export function goodsUpdateStatus (params) {
return request({
url: goodsApi.updateStatus,
method: 'post',
data: params
})
}
export function goodsCheckGoodsCode (params) {
return request({
url: goodsApi.checkGoodsCode,
method: 'post',
data: params
})
}
export function goodsCheckGoodsBarCode (params) {
return request({
url: goodsApi.checkGoodsBarCode,
method: 'post',
data: params
})
}
export function goodsCount (params) {
return request({
url: goodsApi.goodsCount,
method: 'post',
data: params
})
}
export function goodsDetail (params) {
return request({
url: goodsApi.detail,
method: 'post',
data: params
})
}
export function getGoodsListByStoreId (params) {
return request({
url: goodsApi.listByStoreId,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
const goodsCategoryApi = {
add: '/gms/goodsCategory/save',
get: '/gms/goodsCategory/get',
update: '/gms/goodsCategory/update',
del: '/gms/goodsCategory/delete',
list: '/gms/goodsCategory/listGoodsCategory',
updateStatus: '/gms/goodsCategory/updategoodsCategoryStatus'
}
export function goodsCategoryAdd (params) {
return request({
url: goodsCategoryApi.add,
method: 'post',
data: params
})
}
export function goodsCategoryGet (params) {
return request({
url: goodsCategoryApi.get,
method: 'post',
data: params
})
}
export function goodsCategoryUpdate (params) {
return request({
url: goodsCategoryApi.update,
method: 'post',
data: params
})
}
export function goodsCategoryDelete (params) {
return request({
url: goodsCategoryApi.del,
method: 'post',
data: params
})
}
export function goodsCategoryList (params) {
return request({
url: goodsCategoryApi.list,
method: 'post',
data: params
})
}
export function goodsCategoryUpdateStatus (params) {
return request({
url: goodsCategoryApi.updateStatus,
method: 'post',
data: params
})
}

19
src/api/gms/goodsStock.js Normal file
View File

@ -0,0 +1,19 @@
import request from '@/utils/request'
const skuApi = {
page: '/gms/goods/pageGoodsStock',
exportExcel: '/gms/goods/exportGoodsStock'
}
export function pageGoodsStock (params) {
return request({
url: skuApi.page,
method: 'post',
data: params
})
}
export function exportStockExcel (params) {
return request({
url: skuApi.exportExcel,
method: 'post',
data: params
})
}

60
src/api/gms/goodsUnit.js Normal file
View File

@ -0,0 +1,60 @@
import request from '@/utils/request'
const goodsUnitApi = {
add: '/gms/goodsUnit/save',
get: '/gms/goodsUnit/get',
update: '/gms/goodsUnit/update',
del: '/gms/goodsUnit/delete',
page: '/gms/goodsUnit/page',
list: '/gms/goodsUnit/list',
updateStatus: '/gms/goodsUnit/updategoodsUnitStatus'
}
export function goodsUnitAdd (params) {
return request({
url: goodsUnitApi.add,
method: 'post',
data: params
})
}
export function goodsUnitGet (params) {
return request({
url: goodsUnitApi.get,
method: 'post',
data: params
})
}
export function goodsUnitUpdate (params) {
return request({
url: goodsUnitApi.update,
method: 'post',
data: params
})
}
export function goodsUnitDelete (params) {
return request({
url: goodsUnitApi.del,
method: 'post',
data: params
})
}
export function goodsUnitPage (params) {
return request({
url: goodsUnitApi.page,
method: 'post',
data: params
})
}
export function goodsUnitList (params) {
return request({
url: goodsUnitApi.list,
method: 'post',
data: params
})
}
export function goodsUnitUpdateStatus (params) {
return request({
url: goodsUnitApi.updateStatus,
method: 'post',
data: params
})
}

52
src/api/gms/salesProp.js Normal file
View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
const salesPropApi = {
add: '/gms/salesProp/add',
get: '/gms/salesProp/get',
update: '/gms/salesProp/update',
del: '/gms/salesProp/delete',
page: '/gms/salesProp/page',
list: '/gms/salesProp/list'
}
export function salesPropAdd (params) {
return request({
url: salesPropApi.add,
method: 'post',
data: params
})
}
export function salesPropGet (params) {
return request({
url: salesPropApi.get,
method: 'post',
data: params
})
}
export function salesPropUpdate (params) {
return request({
url: salesPropApi.update,
method: 'post',
data: params
})
}
export function salesPropDelete (params) {
return request({
url: salesPropApi.del,
method: 'post',
data: params
})
}
export function salesPropPage (params) {
return request({
url: salesPropApi.page,
method: 'post',
data: params
})
}
export function salesPropList (params) {
return request({
url: salesPropApi.list,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
const salesPropValueApi = {
add: '/gms/salesPropValue/add',
get: '/gms/salesPropValue/get',
update: '/gms/salesPropValue/update',
del: '/gms/salesPropValue/delete',
page: '/gms/salesPropValue/page',
list: '/gms/salesPropValue/list'
}
export function salesPropValueAdd (params) {
return request({
url: salesPropValueApi.add,
method: 'post',
data: params
})
}
export function salesPropValueGet (params) {
return request({
url: salesPropValueApi.get,
method: 'post',
data: params
})
}
export function salesPropValueUpdate (params) {
return request({
url: salesPropValueApi.update,
method: 'post',
data: params
})
}
export function salesPropValueDelete (params) {
return request({
url: salesPropValueApi.del,
method: 'post',
data: params
})
}
export function salesPropValuePage (params) {
return request({
url: salesPropValueApi.page,
method: 'post',
data: params
})
}
export function salesPropValueList (params) {
return request({
url: salesPropValueApi.list,
method: 'post',
data: params
})
}

84
src/api/gms/sku.js Normal file
View File

@ -0,0 +1,84 @@
import request from '@/utils/request'
const skuApi = {
add: '/gms/sku/save',
get: '/gms/sku/get',
update: '/gms/sku/update',
del: '/gms/sku/delete',
page: '/gms/sku/page',
list: '/gms/sku/list',
getJsonSkuList: '/gms/sku/getJsonSkuListByParams',
getSalesPropForAdm: '/gms/sku/getSalesPropForAdm',
getSkuBySalesProp: '/gms/sku/getSkuBySalesProp',
getPropForAdm: '/gms/sku/getPropForAdm'
}
export function skuAdd (params) {
return request({
url: skuApi.add,
method: 'post',
data: params
})
}
export function skuGet (params) {
return request({
url: skuApi.get,
method: 'post',
data: params
})
}
export function skuUpdate (params) {
return request({
url: skuApi.update,
method: 'post',
data: params
})
}
export function skuDelete (params) {
return request({
url: skuApi.del,
method: 'post',
data: params
})
}
export function skuPage (params) {
return request({
url: skuApi.page,
method: 'post',
data: params
})
}
export function skuList (params) {
return request({
url: skuApi.list,
method: 'post',
data: params
})
}
export function skuGetJsonSkuList (params) {
return request({
url: skuApi.getJsonSkuList,
method: 'post',
data: params
})
}
export function getSalesPropForAdm (params) {
return request({
url: skuApi.getSalesPropForAdm,
method: 'post',
data: params
})
}
export function getSkuBySalesProp (params) {
return request({
url: skuApi.getSkuBySalesProp,
method: 'post',
data: params
})
}
export function getPropForAdm (params) {
return request({
url: skuApi.getPropForAdm,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,36 @@
import request from '@/utils/request'
const skuStockChangeRecordApi = {
page: '/gms/skuStockChangeRecord/page',
get: '/gms/skuStockChangeRecord/get',
change: '/gms/skuStockChangeRecord/outOrInSkuStockChangeRecord',
cancel: '/gms/skuStockChangeRecord/cancelStockChangeRecord'
}
export function skuStockChangeRecordPage (params) {
return request({
url: skuStockChangeRecordApi.page,
method: 'post',
data: params
})
}
export function skuStockChangeRecordGet (params) {
return request({
url: skuStockChangeRecordApi.get,
method: 'post',
data: params
})
}
export function skuStockChangeRecordChange (params) {
return request({
url: skuStockChangeRecordApi.change,
method: 'post',
data: params
})
}
export function skuStockChangeRecordCancel (params) {
return request({
url: skuStockChangeRecordApi.cancel,
method: 'post',
data: params
})
}

19
src/api/gms/warehouse.js Normal file
View File

@ -0,0 +1,19 @@
import request from '@/utils/request'
const skuApi = {
listWarehouse: '/gms/warehouse/listByParams',
findWarehouseListByStoreId: '/gms/warehouse/findWarehouseListByStoreId'
}
export function listWarehouse (params) {
return request({
url: skuApi.listWarehouse,
method: 'post',
data: params
})
}
export function listWarehouseByStoreId (params) {
return request({
url: skuApi.findWarehouseListByStoreId,
method: 'post',
data: params
})
}

View File

@ -1,7 +1,7 @@
import request from '@/utils/request' import request from '@/utils/request'
const userApi = { const userApi = {
Login: '/auth/login', Login: '/login',
Logout: '/auth/logout', Logout: '/auth/logout',
ForgePassword: '/auth/forge-password', ForgePassword: '/auth/forge-password',
Register: '/auth/register', Register: '/auth/register',

46
src/api/oms/salesOrder.js Normal file
View File

@ -0,0 +1,46 @@
import request from '@/utils/request'
const salesOrderApi = {
page: '/oms/order/page',
get: '/oms/order/get',
salesOrderLinePage: '/oms/order/findSalesOrderLinePageBySalesOrderId',
exportSalesOrder: '/oms/order/exportSalesOrder',
createOrder: '/oms/order/createOrder'
}
export function salesOrderPage (params) {
return request({
url: salesOrderApi.page,
method: 'post',
data: params
})
}
export function salesOrderGet (params) {
return request({
url: salesOrderApi.get,
method: 'post',
data: params
})
}
export function salesOrderLinePage (params) {
return request({
url: salesOrderApi.salesOrderLinePage,
method: 'post',
data: params
})
}
export function exportSalesOrder (params) {
var result = request({
url: salesOrderApi.exportSalesOrder,
method: 'post',
data: params
})
return result
}
export function createOrder (params) {
var result = request({
url: salesOrderApi.createOrder,
method: 'post',
data: params
})
return result
}

View File

@ -0,0 +1,28 @@
import request from '@/utils/request'
const purchaseApi = {
page: '/purchase/purchaseOrder/pageByParams',
get: '/purchase/purchaseOrder/get',
purchaseOrderLinePage: '/purchase/purchaseOrder/findPurchaseOrderLineParamsByOrderId'
}
export function purchaseOrderPage (params) {
return request({
url: purchaseApi.page,
method: 'post',
data: params
})
}
export function purchaseOrderGet (params) {
return request({
url: purchaseApi.get,
method: 'post',
data: params
})
}
export function purchaseOrderLinePage (params) {
return request({
url: purchaseApi.purchaseOrderLinePage,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,12 @@
import request from '@/utils/request'
const accessTokenApi = {
get: '/security/accessToken/get'
}
export function get (params) {
return request({
url: accessTokenApi.get,
method: 'post',
data: params
})
}

67
src/api/security/app.js Normal file
View File

@ -0,0 +1,67 @@
import request from '@/utils/request'
const appApi = {
add: '/security/app/save',
get: '/security/app/get',
update: '/security/app/update',
del: '/security/app/delete',
page: '/security/app/page',
updateStatus: '/security/app/updateStatus',
refresh: '/security/app/refreshAccessSecret'
}
export function appAdd (params) {
return request({
url: appApi.add,
method: 'post',
data: params
})
}
export function appGet (params) {
return request({
url: appApi.get,
method: 'post',
data: params
})
}
export function appUpdate (params) {
return request({
url: appApi.update,
method: 'post',
data: params
})
}
export function appDelete (params) {
return request({
url: appApi.del,
method: 'post',
data: params
})
}
export function appPage (params) {
return request({
url: appApi.page,
method: 'post',
data: params
})
}
export function appUpdateStatus (params) {
return request({
url: appApi.updateStatus,
method: 'post',
data: params
})
}
export function refreshAccessSecret (params) {
return request({
url: appApi.refresh,
method: 'post',
data: params
})
}
export const appTypeMap = {
'ANDROID_APP': 'Android APP',
'A8_POS': 'POS A8版',
'IOS_APP': 'iPhone APP',
'OPENAPI': '开放接口',
'ADMIN': '管理后台'
}

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
const appVersionApi = {
add: '/security/appVersion/save',
update: '/security/appVersion/update',
del: '/security/appVersion/delete',
page: '/security/appVersion/page',
updateMustUpgrade: '/security/appVersion/updateMustUpgrade',
get: '/security/appVersion/getAppVersionById'
}
export function appVersionAdd (params) {
return request({
url: appVersionApi.add,
method: 'post',
data: params
})
}
export function appVersionUpdate (params) {
return request({
url: appVersionApi.update,
method: 'post',
data: params
})
}
export function appVersionDelete (params) {
return request({
url: appVersionApi.del,
method: 'post',
data: params
})
}
export function appVersionPage (params) {
return request({
url: appVersionApi.page,
method: 'post',
data: params
})
}
export function updateMustUpgrade (params) {
return request({
url: appVersionApi.updateMustUpgrade,
method: 'post',
data: params
})
}
export function appVersionGet (params) {
return request({
url: appVersionApi.get,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,64 @@
import request from '@/utils/request'
const cmsArticleApi = {
add: '/security/cmsArticle/add',
get: '/security/cmsArticle/get',
update: '/security/cmsArticle/update',
del: '/security/cmsArticle/delete',
page: '/security/cmsArticle/page',
updateStatus: '/security/cmsArticle/updateStatus',
listByCode: '/security/cmsArticle/listByCode'
}
export function cmsArticleAdd (params) {
return request({
url: cmsArticleApi.add,
method: 'post',
data: params
})
}
export function cmsArticleGet (params) {
return request({
url: cmsArticleApi.get,
method: 'post',
data: params
})
}
export function cmsArticleUpdate (params) {
return request({
url: cmsArticleApi.update,
method: 'post',
data: params
})
}
export function cmsArticleDelete (params) {
return request({
url: cmsArticleApi.del,
method: 'post',
data: params
})
}
export function cmsArticlePage (params) {
return request({
url: cmsArticleApi.page,
method: 'post',
data: params
})
}
export function cmsArticleUpdateStatus (params) {
return request({
url: cmsArticleApi.updateStatus,
method: 'post',
data: params
})
}
export function listByCode (params) {
return request({
url: cmsArticleApi.listByCode,
method: 'post',
data: params
})
}
export const articleTypeMap = {
0: '固化',
1: '自定义'
}

View File

@ -0,0 +1,12 @@
import request from '@/utils/request'
const deviceInfoApi = {
page: '/security/deviceInfo/page'
}
export function page (params) {
return request({
url: deviceInfoApi.page,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
const api = {
add: '/security/function/add',
update: '/security/function/update',
del: '/security/function/delete',
page: '/security/function/page',
get: '/security/function/get',
functionCodeMap: '/security/function/getFunctionCodeMap'
}
export function functionAdd (params) {
return request({
url: api.add,
method: 'post',
data: params
})
}
export function functionUpdate (params) {
return request({
url: api.update,
method: 'post',
data: params
})
}
export function functionDel (params) {
return request({
url: api.del,
method: 'post',
data: params
})
}
export function functionPage (params) {
return request({
url: api.page,
method: 'post',
data: params
})
}
export function functionGet (params) {
return request({
url: api.get,
method: 'post',
data: params
})
}
export function functionCodeMap (params) {
return request({
url: api.functionCodeMap,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
const functionCategoryApi = {
add: '/security/functionCategory/add',
update: '/security/functionCategory/update',
del: '/security/functionCategory/delete',
page: '/security/functionCategory/page',
get: '/security/functionCategory/get'
}
export function functionCategoryAdd (params) {
return request({
url: functionCategoryApi.add,
method: 'post',
data: params
})
}
export function functionCategoryUpdate (params) {
return request({
url: functionCategoryApi.update,
method: 'post',
data: params
})
}
export function functionCategoryDel (params) {
return request({
url: functionCategoryApi.del,
method: 'post',
data: params
})
}
export function functionCategoryPage (params) {
return request({
url: functionCategoryApi.page,
method: 'post',
data: params
})
}
export function functionCategoryGet (params) {
return request({
url: functionCategoryApi.get,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,21 @@
import request from '@/utils/request'
const functionResourceApi = {
add: '/security/functionResource/add',
del: '/security/functionResource/delete'
}
export function functionResourceAdd (params) {
return request({
url: functionResourceApi.add,
method: 'post',
data: params
})
}
export function functionResourceDelete (params) {
return request({
url: functionResourceApi.del,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,44 @@
import request from '@/utils/request'
const messageApi = {
add: '/security/message/save',
get: '/security/message/get',
update: '/security/message/update',
del: '/security/message/delete',
page: '/security/message/page'
}
export function messageAdd (params) {
return request({
url: messageApi.add,
method: 'post',
data: params
})
}
export function messageGet (params) {
return request({
url: messageApi.get,
method: 'post',
data: params
})
}
export function messageUpdate (params) {
return request({
url: messageApi.update,
method: 'post',
data: params
})
}
export function messageDelete (params) {
return request({
url: messageApi.del,
method: 'post',
data: params
})
}
export function messagePage (params) {
return request({
url: messageApi.page,
method: 'post',
data: params
})
}

21
src/api/security/redis.js Normal file
View File

@ -0,0 +1,21 @@
import request from '@/utils/request'
const redisManageApi = {
page: '/security/redisManage/page',
deleteByParams: '/security/redisManage/delete'
}
export function page (params) {
return request({
url: redisManageApi.page,
method: 'post',
data: params
})
}
export function deleteByParams (params) {
return request({
url: redisManageApi.deleteByParams,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,92 @@
import request from '@/utils/request'
const resourceApi = {
add: '/security/resource/add',
get: '/security/resource/get',
update: '/security/resource/update',
del: '/security/resource/delete',
updateStatus: '/security/resource/updateStatus',
list: '/security/resource/listByParentId',
listByUser: '/security/url/listByUser',
listAllResource: '/security/resource/listAllResource',
resourceByRoleId: '/security/resource/listAllResourceByRoleId',
listResourceByUser: '/security/resource/listResourceByLoginUser',
resourceByFunctionId: '/security/resource/listAllResourceByFunctionId'
}
export function resourceAdd (params) {
return request({
url: resourceApi.add,
method: 'post',
data: params
})
}
export function resourceGet (params) {
return request({
url: resourceApi.get,
method: 'post',
data: params
})
}
export function resourceUpdate (params) {
return request({
url: resourceApi.update,
method: 'post',
data: params
})
}
export function resourceDelete (params) {
return request({
url: resourceApi.del,
method: 'post',
data: params
})
}
export function resourceList (params) {
return request({
url: resourceApi.list,
method: 'post',
data: params
})
}
export function resourceListByUser (params) {
return request({
url: resourceApi.listByUser,
method: 'post',
data: params
})
}
export function resourceAll () {
return request({
url: resourceApi.listAllResource,
method: 'post'
})
}
export function resourceUpdateStatus (params) {
return request({
url: resourceApi.updateStatus,
method: 'post',
data: params
})
}
export function resourceByRoleId (params) {
return request({
url: resourceApi.resourceByRoleId,
method: 'post',
data: params
})
}
export function listResourceByUser (params) {
return request({
url: resourceApi.listResourceByUser,
method: 'post',
data: params
})
}
export function resourceByFunctionId (params) {
return request({
url: resourceApi.resourceByFunctionId,
method: 'post',
data: params
})
}

61
src/api/security/role.js Normal file
View File

@ -0,0 +1,61 @@
import request from '@/utils/request'
const roleApi = {
add: '/security/role/add',
get: '/security/role/get',
update: '/security/role/update',
del: '/security/role/delete',
page: '/security/role/page',
updateStatus: '/security/role/updateStatus',
rolesByUserId: '/security/role/listAllRoleByUserId'
}
export function roleAdd (params) {
return request({
url: roleApi.add,
method: 'post',
data: params
})
}
export function roleGet (params) {
return request({
url: roleApi.get,
method: 'post',
data: params
})
}
export function roleUpdate (params) {
return request({
url: roleApi.update,
method: 'post',
data: params
})
}
export function roleDelete (params) {
return request({
url: roleApi.del,
method: 'post',
data: params
})
}
export function rolePage (params) {
return request({
url: roleApi.page,
method: 'post',
data: params
})
}
export function roleUpdateStatus (params) {
return request({
url: roleApi.updateStatus,
method: 'post',
data: params
})
}
export function rolesByUserId (params) {
return request({
url: roleApi.rolesByUserId,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,21 @@
import request from '@/utils/request'
const roleResourceApi = {
add: '/security/roleResource/add',
del: '/security/roleResource/delete'
}
export function roleResourceAdd (params) {
return request({
url: roleResourceApi.add,
method: 'post',
data: params
})
}
export function roleResourceDelete (params) {
return request({
url: roleResourceApi.del,
method: 'post',
data: params
})
}

100
src/api/security/user.js Normal file
View File

@ -0,0 +1,100 @@
import request from '@/utils/request'
const userApi = {
login: '/login',
logout: '/security/user/logout',
add: '/security/user/add',
get: '/security/user/getById',
update: '/security/user/update',
del: '/security/user/delete',
page: '/security/user/page',
updateEnabled: '/security/user/updateEnabled',
getListByOrgId: '/security/user/getListByOrgId',
getUserInfo: '/security/user/get'
}
const userPasswordApi = {
set: '/security/user/password/set',
update: '/security/user/password/update',
send: '/security/user/sendSecuritycode',
setById: '/security/user/password/setByUserId'
}
export function userLogin (params) {
return request({
url: userApi.login,
method: 'post',
data: params
})
}
export function userAdd (params) {
return request({
url: userApi.add,
method: 'post',
data: params
})
}
export function userGet (params) {
return request({
url: userApi.get,
method: 'post',
data: params
})
}
export function userUpdate (params) {
return request({
url: userApi.update,
method: 'post',
data: params
})
}
export function userDelete (params) {
return request({
url: userApi.del,
method: 'post',
data: params
})
}
export function userPage (params) {
return request({
url: userApi.page,
method: 'post',
data: params
})
}
export function userUpdateEnabled (params) {
return request({
url: userApi.updateEnabled,
method: 'post',
data: params
})
}
export function userPasswordSet (params) {
return request({
url: userPasswordApi.set,
method: 'post',
data: params
})
}
export function userPasswordSetById (params) {
return request({
url: userPasswordApi.setById,
method: 'post',
data: params
})
}
export function getListByOrgId (params) {
return request({
url: userApi.getListByOrgId,
method: 'post',
data: params
})
}
export function getUserInfo (params) {
return request({
url: userApi.getUserInfo,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,20 @@
import request from '@/utils/request'
const userFeedBackApi = {
page: '/security/user/feedback/pageUserFeedBack',
handleFeedBack: '/security/user/feedback/handleFeedBack'
}
export function UserFeedBackPage (params) {
return request({
url: userFeedBackApi.page,
method: 'post',
data: params
})
}
export function handleFeedBack (params) {
return request({
url: userFeedBackApi.handleFeedBack,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,21 @@
import request from '@/utils/request'
const userRoleApi = {
add: '/security/userRole/add',
del: '/security/userRole/delete'
}
export function userRoleAdd (params) {
return request({
url: userRoleApi.add,
method: 'post',
data: params
})
}
export function userRoleDelete (params) {
return request({
url: userRoleApi.del,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,60 @@
import request from '@/utils/request'
const supplierApi = {
add: '/supplier/supplier/add',
get: '/supplier/supplier/getById',
update: '/supplier/supplier/update',
del: '/supplier/supplier/delete',
page: '/supplier/supplier/pageByParams',
updateStatus: '/supplier/supplier/updateStatus',
list: '/supplier/supplier/listSupplierByParams'
}
export function supplierAdd (params) {
return request({
url: supplierApi.add,
method: 'post',
data: params
})
}
export function supplierGet (params) {
return request({
url: supplierApi.get,
method: 'post',
data: params
})
}
export function supplierUpdate (params) {
return request({
url: supplierApi.update,
method: 'post',
data: params
})
}
export function supplierDelete (params) {
return request({
url: supplierApi.del,
method: 'post',
data: params
})
}
export function supplierPage (params) {
return request({
url: supplierApi.page,
method: 'post',
data: params
})
}
export function supplierUpdateStatus (params) {
return request({
url: supplierApi.updateStatus,
method: 'post',
data: params
})
}
export function supplierList (params) {
return request({
url: supplierApi.list,
method: 'post',
data: params
})
}

View File

@ -0,0 +1,46 @@
<template>
<tooltip v-if="tips !== ''">
<template slot="title">{{ tips }}</template>
<avatar :size="avatarSize" :src="src" />
</tooltip>
<avatar v-else :size="avatarSize" :src="src" />
</template>
<script>
import Avatar from 'ant-design-vue/es/avatar'
import Tooltip from 'ant-design-vue/es/tooltip'
export default {
name: 'AvatarItem',
components: {
Avatar,
Tooltip
},
props: {
tips: {
type: String,
default: '',
required: false
},
src: {
type: String,
default: ''
}
},
data () {
return {
size: this.$parent.size
}
},
computed: {
avatarSize () {
return this.size !== 'mini' && this.size || 20
}
},
watch: {
'$parent.size' (val) {
this.size = val
}
}
}
</script>

View File

@ -0,0 +1,99 @@
<!--
<template>
<div :class="[prefixCls]">
<ul>
<slot></slot>
<template v-for="item in filterEmpty($slots.default).slice(0, 3)"></template>
<template v-if="maxLength > 0 && filterEmpty($slots.default).length > maxLength">
<avatar-item :size="size">
<avatar :size="size !== 'mini' && size || 20" :style="excessItemsStyle">{{ `+${maxLength}` }}</avatar>
</avatar-item>
</template>
</ul>
</div>
</template>
-->
<script>
import Avatar from 'ant-design-vue/es/avatar'
import AvatarItem from './Item'
import { filterEmpty } from '@/components/_util/util'
export default {
AvatarItem,
name: 'AvatarList',
components: {
Avatar,
AvatarItem
},
props: {
prefixCls: {
type: String,
default: 'ant-pro-avatar-list'
},
/**
* 头像大小 类型: largesmall mini, default
* 默认值: default
*/
size: {
type: [String, Number],
default: 'default'
},
/**
* 要显示的最大项目
*/
maxLength: {
type: Number,
default: 0
},
/**
* 多余的项目风格
*/
excessItemsStyle: {
type: Object,
default: () => {
return {
color: '#f56a00',
backgroundColor: '#fde3cf'
}
}
}
},
data () {
return {}
},
methods: {
getItems (items) {
const classString = {
[`${this.prefixCls}-item`]: true,
[`${this.size}`]: true
}
if (this.maxLength > 0) {
items = items.slice(0, this.maxLength)
items.push((<Avatar size={ this.size } style={ this.excessItemsStyle }>{`+${this.maxLength}`}</Avatar>))
}
const itemList = items.map((item) => (
<li class={ classString }>{ item }</li>
))
return itemList
}
},
render () {
const { prefixCls, size } = this.$props
const classString = {
[`${prefixCls}`]: true,
[`${size}`]: true
}
const items = filterEmpty(this.$slots.default)
const itemsDom = items && items.length ? <ul class={`${prefixCls}-items`}>{ this.getItems(items) }</ul> : null
return (
<div class={ classString }>
{ itemsDom }
</div>
)
}
}
</script>

View File

@ -10,43 +10,20 @@
</template> </template>
<script> <script>
import moment from 'moment'
const data = []
const beginDay = new Date().getTime()
for (let i = 0; i < 10; i++) {
data.push({
x: moment(new Date(beginDay + 1000 * 60 * 60 * 24 * i)).format('YYYY-MM-DD'),
y: Math.round(Math.random() * 10)
})
}
const tooltip = [
'x*y',
(x, y) => ({
name: x,
value: y
})
]
const scale = [{
dataKey: 'x',
min: 2
}, {
dataKey: 'y',
title: '时间',
min: 1,
max: 30
}]
export default { export default {
name: 'MiniBar', name: 'MiniBar',
props: {
data: {
type: Array,
required: true
},
height: {
type: Number,
default: 100
}
},
data () { data () {
return { return {
data,
tooltip,
scale,
height: 100
} }
} }
} }

View File

@ -14,7 +14,6 @@
<script> <script>
export default { export default {
name: 'RankList', name: 'RankList',
// ['title', 'list']
props: { props: {
title: { title: {
type: String, type: String,
@ -29,23 +28,22 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.rank { .rank {
padding: 0 32px 32px 72px; .title{
padding: 10px 24px;
border-bottom: 1px solid #e8e8e8;
margin: 0;
}
.list { .list {
margin: 25px 0 0; padding: 20px 30px 30px 40px;
padding: 0;
list-style: none; list-style: none;
margin: 0;
li { li {
margin-top: 16px; margin-top: 16px;
span { span {
color: rgba(0, 0, 0, .65); color: rgba(0, 0, 0, .65);
font-size: 14px; font-size: 14px;
line-height: 22px; line-height: 22px;
&:first-child { &:first-child {
background-color: #f5f5f5; background-color: #f5f5f5;
border-radius: 20px; border-radius: 20px;

View File

@ -6,8 +6,5 @@
position: absolute; position: absolute;
bottom: -28px; bottom: -28px;
width: 100%; width: 100%;
/* margin: 0 -5px;
overflow: hidden;*/
} }
} }

View File

@ -0,0 +1,102 @@
<template>
<span>
{{ lastTime | format }}
</span>
</template>
<script>
function fixedZero (val) {
return val * 1 < 10 ? `0${val}` : val
}
export default {
name: 'CountDown',
props: {
format: {
type: Function,
default: undefined
},
target: {
type: [Date, Number],
required: true
},
onEnd: {
type: Function,
default: () => ({})
}
},
data () {
return {
dateTime: '0',
originTargetTime: 0,
lastTime: 0,
timer: 0,
interval: 1000
}
},
filters: {
format (time) {
const hours = 60 * 60 * 1000
const minutes = 60 * 1000
const h = Math.floor(time / hours)
const m = Math.floor((time - h * hours) / minutes)
const s = Math.floor((time - h * hours - m * minutes) / 1000)
return `${fixedZero(h)}:${fixedZero(m)}:${fixedZero(s)}`
}
},
created () {
this.initTime()
this.tick()
},
methods: {
initTime () {
let lastTime = 0
let targetTime = 0
this.originTargetTime = this.target
try {
if (Object.prototype.toString.call(this.target) === '[object Date]') {
targetTime = this.target
} else {
targetTime = new Date(this.target).getTime()
}
} catch (e) {
throw new Error('invalid target prop')
}
lastTime = targetTime - new Date().getTime()
this.lastTime = lastTime < 0 ? 0 : lastTime
},
tick () {
const { onEnd } = this
this.timer = setTimeout(() => {
if (this.lastTime < this.interval) {
clearTimeout(this.timer)
this.lastTime = 0
if (typeof onEnd === 'function') {
onEnd()
}
} else {
this.lastTime -= this.interval
this.tick()
}
}, this.interval)
}
},
beforeUpdate () {
if (this.originTargetTime !== this.target) {
this.initTime()
}
},
beforeDestroy () {
clearTimeout(this.timer)
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,3 @@
import CountDown from './CountDown'
export default CountDown

View File

@ -0,0 +1,34 @@
# CountDown 倒计时
倒计时组件。
引用方式:
```javascript
import CountDown from '@/components/CountDown/CountDown'
export default {
components: {
CountDown
}
}
```
## 代码演示 [demo](https://pro.loacg.com/test/home)
```html
<count-down :target="new Date().getTime() + 3000000" :on-end="onEndHandle" />
```
## API
| 参数 | 说明 | 类型 | 默认值 |
|----------|------------------------------------------|-------------|-------|
| target | 目标时间 | Date | - |
| onEnd | 倒计时结束回调 | funtion | -|

View File

@ -0,0 +1,153 @@
<template>
<div :class="['description-list', size, layout === 'vertical' ? 'vertical': 'horizontal']">
<div v-if="title" class="title">{{ title }}</div>
<a-row>
<slot></slot>
</a-row>
</div>
</template>
<script>
import { Col } from 'ant-design-vue/es/grid/'
const Item = {
name: 'DetailListItem',
props: {
term: {
type: String,
default: '',
required: false
}
},
inject: {
col: {
type: Number
}
},
render () {
return (
<Col {...{ props: responsive[this.col] }}>
<div class="term">{this.$props.term}</div>
<div class="content">{this.$slots.default}</div>
</Col>
)
}
}
const responsive = {
1: { xs: 24 },
2: { xs: 24, sm: 12 },
3: { xs: 24, sm: 12, md: 8 },
4: { xs: 24, sm: 12, md: 6 }
}
export default {
name: 'DetailList',
Item: Item,
components: {
Col
},
props: {
title: {
type: String,
default: '',
required: false
},
col: {
type: Number,
required: false,
default: 3
},
size: {
type: String,
required: false,
default: 'large'
},
layout: {
type: String,
required: false,
default: 'horizontal'
}
},
provide () {
return {
col: this.col > 4 ? 4 : this.col
}
}
}
</script>
<style lang="less" scoped>
.description-list {
.title {
color: rgba(0,0,0,.85);
font-size: 14px;
font-weight: 500;
margin-bottom: 16px;
}
/deep/ .term {
color: rgba(0,0,0,.85);
display: table-cell;
line-height: 20px;
margin-right: 8px;
padding-bottom: 16px;
white-space: nowrap;
&:not(:empty):after {
content: ":";
margin: 0 8px 0 2px;
position: relative;
top: -.5px;
}
}
/deep/ .content {
color: rgba(0,0,0,.65);
display: table-cell;
min-height: 22px;
line-height: 22px;
padding-bottom: 16px;
width: 100%;
&:empty {
content: ' ';
height: 38px;
padding-bottom: 16px;
}
}
&.small {
.title {
font-size: 14px;
color: rgba(0, 0, 0, .65);
font-weight: normal;
margin-bottom: 12px;
}
/deep/ .term, .content {
padding-bottom: 8px;
}
}
&.large {
/deep/ .term, .content {
padding-bottom: 16px;
}
.title {
font-size: 16px;
}
}
&.vertical {
.term {
padding-bottom: 8px;
}
/deep/ .term, .content {
display: block;
}
}
}
</style>

View File

@ -0,0 +1,2 @@
import DescriptionList from './DescriptionList'
export default DescriptionList

View File

@ -9,7 +9,6 @@
@ready="onEditorReady($event)" @ready="onEditorReady($event)"
@change="onEditorChange($event)"> @change="onEditorChange($event)">
</quill-editor> </quill-editor>
</div> </div>
</template> </template>
@ -72,6 +71,7 @@ export default {
/* 覆盖 quill 默认边框圆角为 ant 默认圆角,用于统一 ant 组件风格 */ /* 覆盖 quill 默认边框圆角为 ant 默认圆角,用于统一 ant 组件风格 */
.ant-editor-quill { .ant-editor-quill {
line-height: initial;
/deep/ .ql-toolbar.ql-snow { /deep/ .ql-toolbar.ql-snow {
border-radius: @border-radius-base @border-radius-base 0 0; border-radius: @border-radius-base @border-radius-base 0 0;
} }

View File

@ -1,11 +1,10 @@
<template> <template>
<div :class="prefixCls"> <div :class="prefixCls"><div ref="editor" class="editor-wrapper"></div></div>
<div ref="editor" class="editor-wrapper"></div>
</div>
</template> </template>
<script> <script>
import WEditor from 'wangeditor' import WEditor from 'wangeditor'
import { fileUpload } from '@/api/file/file'
export default { export default {
name: 'WangEditor', name: 'WangEditor',
@ -14,15 +13,19 @@ export default {
type: String, type: String,
default: 'ant-editor-wang' default: 'ant-editor-wang'
}, },
// eslint-disable-next-line
value: { value: {
type: String type: String,
default: ''
},
groupName: {
type: String,
required: true
} }
}, },
data () { data () {
return { return {
editor: null, editor: null,
editorContent: null editorContent: ''
} }
}, },
watch: { watch: {
@ -35,12 +38,27 @@ export default {
this.initEditor() this.initEditor()
}, },
methods: { methods: {
content () {
return this.editorContent
},
initEditor () { initEditor () {
this.editor = new WEditor(this.$refs.editor) this.editor = new WEditor(this.$refs.editor)
// this.editor.onchangeTimeout = 200 this.editor.customConfig.uploadImgMaxLength = 10
this.editor.customConfig.onchange = (html) => { this.editor.customConfig.zIndex = 100
this.editor.customConfig.customUploadImg = (files, insert) => {
const formData = new FormData()
files.forEach(file => {
formData.append('files', file)
})
formData.append('groupName', this.groupName)
fileUpload(formData).then((res) => {
res.data.forEach((url) => {
insert(url)
})
})
}
this.editor.customConfig.onchange = html => {
this.editorContent = html this.editorContent = html
this.$emit('change', this.editorContent)
} }
this.editor.create() this.editor.create()
} }
@ -48,10 +66,16 @@ export default {
} }
</script> </script>
<style lang="less" scoped> <style>
.ant-editor-wang { .ant-editor-wang {
.editor-wrapper { .editor-wrapper {
text-align: left; text-align: left;
} }
} }
.w-e-toolbar {
display: -ms-flexbox;
display: flex;
padding: 0 5px;
flex-wrap: wrap;
}
</style> </style>

View File

@ -0,0 +1,130 @@
<template>
<div class="exception">
<div class="imgBlock">
<div class="imgEle" :style="{backgroundImage: `url(${config[type].img})`}">
</div>
</div>
<div class="content">
<h1>{{ config[type].title }}</h1>
<div class="desc">{{ config[type].desc }}</div>
<div class="actions">
<a-button type="primary" @click="handleToHome">返回首页</a-button>
</div>
</div>
</div>
</template>
<script>
import types from './type'
export default {
name: 'Exception',
props: {
type: {
type: String,
default: '404'
}
},
data () {
return {
config: types
}
},
methods: {
handleToHome () {
this.$router.push({ name: 'dashboard' })
}
}
}
</script>
<style lang="less">
@import "~ant-design-vue/lib/style/index";
.exception {
display: flex;
align-items: center;
height: 80%;
min-height: 500px;
.imgBlock {
flex: 0 0 62.5%;
width: 62.5%;
padding-right: 152px;
zoom: 1;
&::before,
&::after {
content: ' ';
display: table;
}
&::after {
clear: both;
height: 0;
font-size: 0;
visibility: hidden;
}
}
.imgEle {
float: right;
width: 100%;
max-width: 430px;
height: 360px;
background-repeat: no-repeat;
background-position: 50% 50%;
background-size: contain;
}
.content {
flex: auto;
h1 {
margin-bottom: 24px;
color: #434e59;
font-weight: 600;
font-size: 72px;
line-height: 72px;
}
.desc {
margin-bottom: 16px;
color: @text-color-secondary;
font-size: 20px;
line-height: 28px;
}
.actions {
button:not(:last-child) {
margin-right: 8px;
}
}
}
}
@media screen and (max-width: @screen-xl) {
.exception {
.imgBlock {
padding-right: 88px;
}
}
}
@media screen and (max-width: @screen-sm) {
.exception {
display: block;
text-align: center;
.imgBlock {
margin: 0 auto 24px;
padding-right: 0;
}
}
}
@media screen and (max-width: @screen-xs) {
.exception {
.imgBlock {
margin-bottom: -24px;
overflow: hidden;
}
}
}
</style>

View File

@ -0,0 +1,2 @@
import ExceptionPage from './ExceptionPage.vue'
export default ExceptionPage

View File

@ -0,0 +1,28 @@
const types = {
401: {
title: '401',
desc: '未登录或登录超时'
},
403: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/wZcnGqRDyhPOEYFcZDnb.svg',
title: '403',
desc: '抱歉,你无权访问该页面'
},
404: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg',
title: '404',
desc: '抱歉,你访问的页面不存在或仍在开发中'
},
500: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
title: '500',
desc: '抱歉,服务器出错了'
},
503: {
img: 'https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg',
title: '503',
desc: '抱歉,服务器出错了'
}
}
export default types

View File

@ -0,0 +1,42 @@
<template>
<div class="footer">
<div class="copyright"><a href="http://one.tcc-cloud.com/" target="_blank">TCC 西安研发中心出品</a></div>
</div>
</template>
<script>
export default {
name: 'GlobalFooter',
data () {
return {}
}
}
</script>
<style lang="less" scoped>
.footer {
padding: 0 16px;
margin: 48px 0 24px;
text-align: center;
.links {
margin-bottom: 8px;
a {
color: rgba(0, 0, 0, 0.45);
&:hover {
color: rgba(0, 0, 0, 0.65);
}
&:not(:last-child) {
margin-right: 40px;
}
}
}
.copyright {
color: rgba(0, 0, 0, 0.45);
font-size: 14px;
}
}
</style>

View File

@ -0,0 +1,2 @@
import GlobalFooter from './GlobalFooter'
export default GlobalFooter

View File

@ -1,12 +1,8 @@
<template> <template>
<global-footer class="footer custom-render"> <global-footer class="footer custom-render">
<template v-slot:links> <template v-slot:links></template>
<a href="https://www.github.com/vueComponent/pro-layout" target="_blank">Pro Layout</a>
<a href="https://www.github.com/vueComponent/ant-design-vue-pro" target="_blank">Github</a>
<a href="https://www.github.com/sendya/" target="_blank">@Sendya</a>
</template>
<template v-slot:copyright> <template v-slot:copyright>
<a href="https://github.com/vueComponent" target="_blank">vueComponent</a> <a href="http://one.tcc-cloud.com/" target="_blank">TCC 西安研发中心出品</a>
</template> </template>
</global-footer> </global-footer>
</template> </template>

View File

@ -1,18 +1,14 @@
<template> <template>
<a-dropdown v-if="currentUser && currentUser.name" placement="bottomRight"> <a-dropdown v-if="currentUser && currentUser.username" placement="bottomRight">
<span class="ant-pro-account-avatar"> <span class="ant-pro-account-avatar">
<a-avatar size="small" src="https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png" class="antd-pro-global-header-index-avatar" /> <a-avatar size="small" src="https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png" class="antd-pro-global-header-index-avatar" />
<span>{{ currentUser.name }}</span> <span>{{ currentUser.username }}</span>
</span> </span>
<template v-slot:overlay> <template v-slot:overlay>
<a-menu class="ant-pro-drop-down menu" :selected-keys="[]"> <a-menu class="ant-pro-drop-down menu">
<a-menu-item v-if="menu" key="center" @click="handleToCenter"> <a-menu-item key="setting" @click="handlePassword">
<a-icon type="user" />
个人中心
</a-menu-item>
<a-menu-item v-if="menu" key="settings" @click="handleToSettings">
<a-icon type="setting" /> <a-icon type="setting" />
个人设置 修改密码
</a-menu-item> </a-menu-item>
<a-menu-divider v-if="menu" /> <a-menu-divider v-if="menu" />
<a-menu-item key="logout" @click="handleLogout"> <a-menu-item key="logout" @click="handleLogout">
@ -28,10 +24,11 @@
</template> </template>
<script> <script>
import { Modal } from 'ant-design-vue'
export default { export default {
name: 'AvatarDropdown', name: 'AvatarDropdown',
components: {
},
props: { props: {
currentUser: { currentUser: {
type: Object, type: Object,
@ -43,26 +40,20 @@ export default {
} }
}, },
methods: { methods: {
handleToCenter () {
this.$router.push({ path: '/account/center' })
},
handleToSettings () {
this.$router.push({ path: '/account/settings' })
},
handleLogout (e) { handleLogout (e) {
Modal.confirm({ this.$confirm({
title: this.$t('layouts.usermenu.dialog.title'), title: this.$t('layouts.usermenu.dialog.title'),
content: this.$t('layouts.usermenu.dialog.content'), content: this.$t('layouts.usermenu.dialog.content'),
onOk: () => { onOk: () => {
// return new Promise((resolve, reject) => {
// setTimeout(Math.random() > 0.5 ? resolve : reject, 1500)
// }).catch(() => console.log('Oops errors!'))
return this.$store.dispatch('Logout').then(() => { return this.$store.dispatch('Logout').then(() => {
this.$router.push({ name: 'login' }) this.$router.push({ name: 'login' })
}) })
}, },
onCancel () {} onCancel () {}
}) })
},
handlePassword () {
this.$emit('handlePassword')
} }
} }
} }

View File

@ -0,0 +1,125 @@
<template>
<transition name="showHeader">
<div v-if="visible" class="header-animat">
<a-layout-header
v-if="visible"
:class="[fixedHeader && 'ant-header-fixedHeader', sidebarOpened ? 'ant-header-side-opened' : 'ant-header-side-closed', ]"
:style="{ padding: '0' }">
<div v-if="mode === 'sidemenu'" class="header">
<a-icon v-if="device==='mobile'" class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle"/>
<a-icon v-else class="trigger" :type="collapsed ? 'menu-unfold' : 'menu-fold'" @click="toggle"/>
<user-menu></user-menu>
</div>
<div v-else :class="['top-nav-header-index', theme]">
<div class="header-index-wide">
<div class="header-index-left">
<logo class="top-nav-header" :show-title="device !== 'mobile'"/>
<s-menu v-if="device !== 'mobile'" mode="horizontal" :menu="menus" :theme="theme" />
<a-icon v-else class="trigger" :type="collapsed ? 'menu-fold' : 'menu-unfold'" @click="toggle" />
</div>
<user-menu class="header-index-right"></user-menu>
</div>
</div>
</a-layout-header>
</div>
</transition>
</template>
<script>
import UserMenu from '../tools/UserMenu'
import SMenu from '../Menu/'
import Logo from '../tools/Logo'
import { mixin } from '@/utils/mixin'
export default {
name: 'GlobalHeader',
components: {
UserMenu,
SMenu,
Logo
},
mixins: [mixin],
props: {
mode: {
type: String,
// sidemenu, topmenu
default: 'sidemenu'
},
menus: {
type: Array,
required: true
},
theme: {
type: String,
required: false,
default: 'dark'
},
collapsed: {
type: Boolean,
required: false,
default: false
},
device: {
type: String,
required: false,
default: 'desktop'
}
},
data () {
return {
visible: true,
oldScrollTop: 0
}
},
mounted () {
document.addEventListener('scroll', this.handleScroll, { passive: true })
},
methods: {
handleScroll () {
if (!this.autoHideHeader) {
return
}
const scrollTop = document.body.scrollTop + document.documentElement.scrollTop
if (!this.ticking) {
this.ticking = true
requestAnimationFrame(() => {
if (this.oldScrollTop > scrollTop) {
this.visible = true
} else if (scrollTop > 300 && this.visible) {
this.visible = false
} else if (scrollTop < 300 && !this.visible) {
this.visible = true
}
this.oldScrollTop = scrollTop
this.ticking = false
})
}
},
toggle () {
this.$emit('toggle')
}
},
beforeDestroy () {
document.body.removeEventListener('scroll', this.handleScroll, true)
}
}
</script>
<style lang="less">
@import '../index.less';
.header-animat{
position: relative;
z-index: @ant-global-header-zindex;
}
.showHeader-enter-active {
transition: all 0.25s ease;
}
.showHeader-leave-active {
transition: all 0.5s ease;
}
.showHeader-enter, .showHeader-leave-to {
opacity: 0;
}
</style>

View File

@ -1,7 +1,8 @@
<template> <template>
<div :class="wrpCls"> <div :class="wrpCls">
<avatar-dropdown :menu="showMenu" :current-user="currentUser" :class="prefixCls" /> <avatar-dropdown :menu="showMenu" :current-user="currentUser" :class="prefixCls" @handlePassword="handlePassword"/>
<select-lang :class="prefixCls" /> <select-lang :class="prefixCls" />
<password-form ref="password"></password-form>
</div> </div>
</template> </template>
@ -13,7 +14,8 @@ export default {
name: 'RightContent', name: 'RightContent',
components: { components: {
AvatarDropdown, AvatarDropdown,
SelectLang SelectLang,
PasswordForm: () => import('@/components/PasswordForm')
}, },
props: { props: {
prefixCls: { prefixCls: {
@ -43,16 +45,17 @@ export default {
wrpCls () { wrpCls () {
return { return {
'ant-pro-global-header-index-right': true, 'ant-pro-global-header-index-right': true,
[`ant-pro-global-header-index-${(this.isMobile || !this.topMenu) ? 'light' : this.theme}`]: true [`ant-pro-global-header-index-${this.isMobile || !this.topMenu ? 'light' : this.theme}`]: true
} }
} }
}, },
mounted () { created () {
setTimeout(() => { this.currentUser = this.$store.getters.userInfo || { username: '***' }
this.currentUser = { },
name: 'Serati Ma' methods: {
handlePassword () {
this.$refs.password.show(this.currentUser.userId)
} }
}, 1500)
} }
} }
</script> </script>

View File

@ -0,0 +1,2 @@
import GlobalHeader from './GlobalHeader'
export default GlobalHeader

View File

@ -22,9 +22,9 @@ export default {
type: String, type: String,
default: 'ant-pro-icon-selector' default: 'ant-pro-icon-selector'
}, },
// eslint-disable-next-line
value: { value: {
type: String type: String,
default: ''
} }
}, },
data () { data () {
@ -59,24 +59,17 @@ export default {
} }
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "../index.less"; @import "../index.less";
ul{ ul{
list-style: none; list-style: none;
padding: 0; padding: 0;
overflow-y: scroll;
height: 250px;
li{ li{
display: inline-block; display: inline-block;
padding: @padding-sm; padding: @padding-sm;
margin: 3px 0; margin: 3px 0;
border-radius: @border-radius-base; border-radius: @border-radius-base;
&:hover, &.active{ &:hover, &.active{
// box-shadow: 0px 0px 5px 2px @primary-color;
cursor: pointer; cursor: pointer;
color: @white; color: @white;
background-color: @primary-color; background-color: @primary-color;

View File

@ -0,0 +1,47 @@
<template>
<a-drawer
title="图标选择"
width="640"
placement="right"
:visible="visible"
class="icon-select-view"
@close="onClose">
<icon-selector @change="handleIconChange"/>
</a-drawer>
</template>
<script>
import IconSelector from './IconSelector'
export default {
name: 'IconSelectorView',
components: {
IconSelector
},
data () {
return {
visible: false
}
},
methods: {
show () {
this.visible = true
},
onClose () {
this.visible = false
},
handleIconChange (icon) {
this.$emit('ok', icon)
this.onClose()
}
}
}
</script>
<style scoped lang="less">
.icon-select-view{
/deep/ .ant-drawer-body{
padding: 0;
}
}
</style>

View File

@ -16,7 +16,7 @@ export default [
{ {
key: 'editor', key: 'editor',
title: '编辑类图标', title: '编辑类图标',
icons: ['edit', 'form', 'copy', 'scissor', 'delete', 'snippets', 'diff', 'highlight', 'align-center', 'align-left', 'align-right', 'bg-colors', 'bold', 'italic', 'underline', 'strikethrough', 'redo', 'undo', 'zoom-in', 'zoom-out', 'font-colors', 'font-size', 'line-height', 'colum-height', 'dash', 'small-dash', 'sort-ascending', 'sort-descending', 'drag', 'ordered-list', 'radius-setting'] icons: ['edit', 'form', 'copy', 'scissor', 'delete', 'snippets', 'diff', 'highlight', 'align-center', 'align-left', 'align-right', 'bg-colors', 'bold', 'italic', 'underline', 'strikethrough', 'redo', 'undo', 'zoom-in', 'zoom-out', 'font-colors', 'font-size', 'line-height', 'column-height', 'dash', 'small-dash', 'sort-ascending', 'sort-descending', 'drag', 'ordered-list', 'radius-setting']
}, },
{ {
key: 'data', key: 'data',
@ -26,7 +26,7 @@ export default [
{ {
key: 'brand_logo', key: 'brand_logo',
title: '网站通用图标', title: '网站通用图标',
icons: ['lock', 'unlock', 'bars', 'book', 'calendar', 'cloud', 'cloud-download', 'code', 'copy', 'credit-card', 'delete', 'desktop', 'download', 'ellipsis', 'file', 'file-text', 'file-unknown', 'file-pdf', 'file-word', 'file-excel', 'file-jpg', 'file-ppt', 'file-markdown', 'file-add', 'folder', 'folder-open', 'folder-add', 'hdd', 'frown', 'meh', 'smile', 'inbox', 'laptop', 'appstore', 'link', 'mail', 'mobile', 'notification', 'paper-clip', 'picture', 'poweroff', 'reload', 'search', 'setting', 'share-alt', 'shopping-cart', 'tablet', 'tag', 'tags', 'to-top', 'upload', 'user', 'video-camera', 'home', 'loading', 'loading-3-quarters', 'cloud-upload', 'star', 'heart', 'environment', 'eye', 'camera', 'save', 'team', 'solution', 'phone', 'filter', 'exception', 'export', 'customer-service', 'qrcode', 'scan', 'like', 'dislike', 'message', 'pay-circle', 'calculator', 'pushpin', 'bulb', 'select', 'switcher', 'rocket', 'bell', 'disconnect', 'database', 'compass', 'barcode', 'hourglass', 'key', 'flag', 'layout', 'printer', 'sound', 'usb', 'skin', 'tool', 'sync', 'wifi', 'car', 'schedule', 'user-add', 'user-delete', 'usergroup-add', 'usergroup-delete', 'man', 'woman', 'shop', 'gift', 'idcard', 'medicine-box', 'red-envelope', 'coffee', 'copyright', 'trademark', 'safety', 'wallet', 'bank', 'trophy', 'contacts', 'global', 'shake', 'api', 'fork', 'dashboard', 'table', 'profile', 'alert', 'audit', 'branches', 'build', 'border', 'crown', 'experiment', 'fire', 'money-collect', 'property-safety', 'read', 'reconciliation', 'rest', 'security-scan', 'insurance', 'interation', 'safety-certificate', 'project', 'thunderbolt', 'block', 'cluster', 'deployment-unit', 'dollar', 'euro', 'pound', 'file-done', 'file-exclamation', 'file-protect', 'file-search', 'file-sync', 'gateway', 'gold', 'robot', 'shopping'] icons: ['lock', 'unlock', 'bars', 'book', 'calendar', 'cloud', 'cloud-download', 'code', 'copy', 'credit-card', 'delete', 'desktop', 'download', 'ellipsis', 'file', 'file-text', 'file-unknown', 'file-pdf', 'file-word', 'file-excel', 'file-jpg', 'file-ppt', 'file-markdown', 'file-add', 'folder', 'folder-open', 'folder-add', 'hdd', 'frown', 'meh', 'smile', 'inbox', 'laptop', 'appstore', 'link', 'mail', 'mobile', 'notification', 'paper-clip', 'picture', 'poweroff', 'reload', 'search', 'setting', 'share-alt', 'shopping-cart', 'tablet', 'tag', 'tags', 'to-top', 'upload', 'user', 'video-camera', 'home', 'loading', 'loading-3-quarters', 'cloud-upload', 'star', 'heart', 'environment', 'eye', 'camera', 'save', 'team', 'solution', 'phone', 'filter', 'exception', 'export', 'customer-service', 'qrcode', 'scan', 'like', 'dislike', 'message', 'pay-circle', 'calculator', 'pushpin', 'bulb', 'select', 'switcher', 'rocket', 'bell', 'disconnect', 'database', 'compass', 'barcode', 'hourglass', 'key', 'flag', 'layout', 'printer', 'sound', 'usb', 'skin', 'tool', 'sync', 'wifi', 'car', 'schedule', 'user-add', 'user-delete', 'usergroup-add', 'usergroup-delete', 'man', 'woman', 'shop', 'gift', 'idcard', 'medicine-box', 'red-envelope', 'coffee', 'copyright', 'trademark', 'safety', 'wallet', 'bank', 'trophy', 'contacts', 'global', 'shake', 'api', 'fork', 'dashboard', 'table', 'profile', 'alert', 'audit', 'branches', 'build', 'border', 'crown', 'experiment', 'fire', 'money-collect', 'property-safety', 'read', 'reconciliation', 'rest', 'security-scan', 'insurance', 'interaction', 'safety-certificate', 'project', 'thunderbolt', 'block', 'cluster', 'deployment-unit', 'dollar', 'euro', 'pound', 'file-done', 'file-exclamation', 'file-protect', 'file-search', 'file-sync', 'gateway', 'gold', 'robot', 'shopping']
}, },
{ {
key: 'application', key: 'application',

View File

@ -0,0 +1,151 @@
<template>
<div class="clearfix">
<a-upload
list-type="picture-card"
:multiple="true"
:file-list="fileList"
:before-upload="beforeUpload"
:preview-file="previewFile"
:remove="handleRemove"
@preview="handlePreview">
<div v-if="limit && fileList.length < limit">
<a-icon type="plus" />
<div class="ant-upload-text">上传文件</div>
</div>
</a-upload>
<a-modal :visible="previewVisible" :footer="null" @cancel="handleCancel">
<img alt="example" style="width: 100%" :src="previewImage" />
</a-modal>
</div>
</template>
<script>
import Upload from 'ant-design-vue/lib/upload'
import 'ant-design-vue/lib/upload/style'
import { fileUpload } from '@/api/file/file'
// function getBase64(file) {
// return new Promise((resolve, reject) => {
// const reader = new FileReader()
// reader.readAsDataURL(file)
// reader.onload = () => resolve(reader.result)
// reader.onerror = error => reject(error)
// })
// }
export default {
components: {
[Upload.name]: Upload
},
props: {
groupName: {
type: String,
default: ''
},
limit: {
type: Number,
default: 10
},
defaultList: {
type: Array,
default () {
return []
}
}
},
data () {
return {
uploading: false,
fileList: [],
previewVisible: false,
previewImage: ''
}
},
methods: {
previewFile (file) {
console.log(file)
},
clear () {
this.fileList = []
},
flush () {
this.clear()
this.defaultList.forEach((file, index) => {
this.fileList.push({
uid: index,
name: 'image.png',
status: 'done',
url: file
})
})
},
handleRemove (file) {
const index = this.fileList.indexOf(file)
const newFileList = this.fileList.slice()
newFileList.splice(index, 1)
this.fileList = newFileList
},
handleCancel () {
this.previewVisible = false
},
beforeUpload (file) {
this.fileList = [...this.fileList, file]
return false
},
async handlePreview (file) {
this.previewImage = file.url
this.previewVisible = true
},
submitUpload () {
return new Promise((resolve, reject) => {
const { fileList } = this
if (fileList.length === 0) {
resolve([])
} else {
const fileUrlArray = []
let count = 0
const formData = new FormData()
fileList.forEach(file => {
if (file instanceof File) {
formData.append('files', file)
count++
} else {
fileUrlArray.push(file.url)
}
})
formData.append('groupName', this.groupName)
if (count > 0) {
this.uploading = true
fileUpload(formData).then((res) => {
resolve(fileUrlArray.concat(res.data))
this.uploading = false
}, (err) => {
reject(err)
this.uploading = false
})
} else {
resolve(fileUrlArray)
}
}
})
}
}
}
</script>
<style scoped>
/* you can make up upload button and sample style by using stylesheets */
.ant-upload-select-picture-card i {
font-size: 32px;
color: #999;
}
.ant-upload-select-picture-card .ant-upload-text {
margin-top: 8px;
color: #666;
}
.ant-upload-list-picture-card .ant-upload-list-item{
width: 90px;
height: 90px;
}
.ant-upload.ant-upload-select-picture-card{
width: 90px;
height: 90px;
}
</style>

View File

@ -0,0 +1,61 @@
<template>
<a-layout-sider
:class="['sider', isDesktop() ? null : 'shadow', theme, fixSiderbar ? 'ant-fixed-sidemenu' : null ]"
width="256px"
:collapsible="collapsible"
v-model="collapsed"
:trigger="null">
<logo />
<s-menu
:collapsed="collapsed"
:menu="menus"
:theme="theme"
:mode="mode"
@select="onSelect"
style="padding: 16px 0px;"></s-menu>
</a-layout-sider>
</template>
<script>
import Logo from '@/components/tools/Logo'
import SMenu from './index'
import { mixin, mixinDevice } from '@/utils/mixin'
export default {
name: 'SideMenu',
components: { Logo, SMenu },
mixins: [mixin, mixinDevice],
props: {
mode: {
type: String,
required: false,
default: 'inline'
},
theme: {
type: String,
required: false,
default: 'dark'
},
collapsible: {
type: Boolean,
required: false,
default: false
},
collapsed: {
type: Boolean,
required: false,
default: false
},
menus: {
type: Array,
required: true
}
},
methods: {
onSelect (obj) {
this.$emit('menuSelect', obj)
}
}
}
</script>

View File

@ -0,0 +1,2 @@
import SMenu from './menu'
export default SMenu

177
src/components/Menu/menu.js Normal file
View File

@ -0,0 +1,177 @@
import Menu from 'ant-design-vue/es/menu'
import Icon from 'ant-design-vue/es/icon'
export default {
name: 'SMenu',
props: {
menu: {
type: Array,
required: true
},
theme: {
type: String,
required: false,
default: 'dark'
},
mode: {
type: String,
required: false,
default: 'inline'
},
collapsed: {
type: Boolean,
required: false,
default: false
}
},
data () {
return {
openKeys: [],
selectedKeys: [],
cachedOpenKeys: []
}
},
computed: {
rootSubmenuKeys: vm => {
const keys = []
vm.menu.forEach(item => keys.push(item.path))
return keys
}
},
mounted () {
this.updateMenu()
},
watch: {
collapsed (val) {
if (val) {
this.cachedOpenKeys = this.openKeys.concat()
this.openKeys = []
} else {
this.openKeys = this.cachedOpenKeys
}
},
$route: function () {
this.updateMenu()
}
},
methods: {
// select menu item
onOpenChange (openKeys) {
// 在水平模式下时执行,并且不再执行后续
if (this.mode === 'horizontal') {
this.openKeys = openKeys
return
}
// 非水平模式时
const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
this.openKeys = openKeys
} else {
this.openKeys = latestOpenKey ? [latestOpenKey] : []
}
},
onSelect ({ item, key, selectedKeys }) {
this.selectedKeys = selectedKeys
this.$emit('select', { item, key, selectedKeys })
},
updateMenu () {
const routes = this.$route.matched.concat()
const { hidden } = this.$route.meta
if (routes.length >= 3 && hidden) {
routes.pop()
this.selectedKeys = [routes[routes.length - 1].path]
} else {
this.selectedKeys = [routes.pop().path]
}
const openKeys = []
if (this.mode === 'inline') {
routes.forEach(item => {
openKeys.push(item.path)
})
}
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
},
// render
renderItem (menu) {
if (!menu.hidden) {
return menu.children && !menu.hideChildrenInMenu ? this.renderSubMenu(menu) : this.renderMenuItem(menu)
}
return null
},
renderMenuItem (menu) {
const target = menu.meta.target || null
const CustomTag = target && 'a' || 'router-link'
const props = { to: { name: menu.name } }
const attrs = { href: menu.path, target: menu.meta.target }
if (menu.children && menu.hideChildrenInMenu) {
// 把有子菜单的 并且 父菜单是要隐藏子菜单的
// 都给子菜单增加一个 hidden 属性
// 用来给刷新页面时, selectedKeys 做控制用
menu.children.forEach(item => {
item.meta = Object.assign(item.meta, { hidden: true })
})
}
return (
<Menu.Item {...{ key: menu.path }}>
<CustomTag {...{ props, attrs }}>
{this.renderIcon(menu.meta.icon)}
<span>{menu.meta.title}</span>
</CustomTag>
</Menu.Item>
)
},
renderSubMenu (menu) {
const itemArr = []
if (!menu.hideChildrenInMenu) {
menu.children.forEach(item => itemArr.push(this.renderItem(item)))
}
return (
<Menu.SubMenu {...{ key: menu.path }}>
<span slot="title">
{this.renderIcon(menu.meta.icon)}
<span>{menu.meta.title}</span>
</span>
{itemArr}
</Menu.SubMenu>
)
},
renderIcon (icon) {
if (icon === 'none' || icon === undefined) {
return null
}
const props = {}
typeof (icon) === 'object' ? props.component = icon : props.type = icon
return (
<Icon {... { props } }/>
)
}
},
render () {
const dynamicProps = {
props: {
mode: this.mode,
theme: this.theme,
openKeys: this.openKeys,
selectedKeys: this.selectedKeys
},
on: {
openChange: this.onOpenChange,
select: this.onSelect
}
}
const menuTree = this.menu.map(item => {
if (item.hidden) {
return null
}
return this.renderItem(item)
})
return (<Menu {...dynamicProps}>{menuTree}</Menu>)
}
}

View File

@ -0,0 +1,156 @@
import Menu from 'ant-design-vue/es/menu'
import Icon from 'ant-design-vue/es/icon'
const { Item, SubMenu } = Menu
export default {
name: 'SMenu',
props: {
menu: {
type: Array,
required: true
},
theme: {
type: String,
required: false,
default: 'dark'
},
mode: {
type: String,
required: false,
default: 'inline'
},
collapsed: {
type: Boolean,
required: false,
default: false
}
},
data () {
return {
openKeys: [],
selectedKeys: [],
cachedOpenKeys: []
}
},
computed: {
rootSubmenuKeys: vm => {
const keys = []
vm.menu.forEach(item => keys.push(item.path))
return keys
}
},
created () {
this.updateMenu()
},
watch: {
collapsed (val) {
if (val) {
this.cachedOpenKeys = this.openKeys.concat()
this.openKeys = []
} else {
this.openKeys = this.cachedOpenKeys
}
},
$route: function () {
this.updateMenu()
}
},
methods: {
renderIcon: function (h, icon) {
if (icon === 'none' || icon === undefined) {
return null
}
const props = {}
typeof (icon) === 'object' ? props.component = icon : props.type = icon
return h(Icon, { props: { ...props } })
},
renderMenuItem: function (h, menu, pIndex, index) {
const target = menu.meta.target || null
return h(Item, { key: menu.path ? menu.path : 'item_' + pIndex + '_' + index }, [
h('router-link', { attrs: { to: { name: menu.name }, target: target } }, [
this.renderIcon(h, menu.meta.icon),
h('span', [menu.meta.title])
])
])
},
renderSubMenu: function (h, menu, pIndex, index) {
const this2_ = this
const subItem = [h('span', { slot: 'title' }, [this.renderIcon(h, menu.meta.icon), h('span', [menu.meta.title])])]
const itemArr = []
const pIndex_ = pIndex + '_' + index
console.log('menu', menu)
if (!menu.hideChildrenInMenu) {
menu.children.forEach(function (item, i) {
itemArr.push(this2_.renderItem(h, item, pIndex_, i))
})
}
return h(SubMenu, { key: menu.path ? menu.path : 'submenu_' + pIndex + '_' + index }, subItem.concat(itemArr))
},
renderItem: function (h, menu, pIndex, index) {
if (!menu.hidden) {
return menu.children && !menu.hideChildrenInMenu
? this.renderSubMenu(h, menu, pIndex, index)
: this.renderMenuItem(h, menu, pIndex, index)
}
},
renderMenu: function (h, menuTree) {
const this2_ = this
const menuArr = []
menuTree.forEach(function (menu, i) {
if (!menu.hidden) {
menuArr.push(this2_.renderItem(h, menu, '0', i))
}
})
return menuArr
},
onOpenChange (openKeys) {
const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key))
if (!this.rootSubmenuKeys.includes(latestOpenKey)) {
this.openKeys = openKeys
} else {
this.openKeys = latestOpenKey ? [latestOpenKey] : []
}
},
updateMenu () {
const routes = this.$route.matched.concat()
if (routes.length >= 4 && this.$route.meta.hidden) {
routes.pop()
this.selectedKeys = [routes[2].path]
} else {
this.selectedKeys = [routes.pop().path]
}
const openKeys = []
if (this.mode === 'inline') {
routes.forEach(item => {
openKeys.push(item.path)
})
}
this.collapsed ? (this.cachedOpenKeys = openKeys) : (this.openKeys = openKeys)
}
},
render (h) {
return h(
Menu,
{
props: {
theme: this.$props.theme,
mode: this.$props.mode,
openKeys: this.openKeys,
selectedKeys: this.selectedKeys
},
on: {
openChange: this.onOpenChange,
select: obj => {
this.selectedKeys = obj.selectedKeys
this.$emit('select', obj)
}
}
},
this.renderMenu(h, this.menu)
)
}
}

View File

@ -0,0 +1,202 @@
<template>
<div class="page-header">
<div class="page-header-index-wide">
<s-breadcrumb />
<div class="detail">
<div class="main" v-if="!$route.meta.hiddenHeaderContent">
<div class="row">
<img v-if="logo" :src="logo" class="logo"/>
<h1 v-if="title" class="title">{{ title }}</h1>
<div class="action">
<slot name="action"></slot>
</div>
</div>
<div class="row">
<div v-if="avatar" class="avatar">
<a-avatar :src="avatar" />
</div>
<div v-if="this.$slots.content" class="headerContent">
<slot name="content"></slot>
</div>
<div v-if="this.$slots.extra" class="extra">
<slot name="extra"></slot>
</div>
</div>
<div>
<slot name="pageMenu"></slot>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Breadcrumb from '@/components/tools/Breadcrumb'
export default {
name: 'PageHeader',
components: {
's-breadcrumb': Breadcrumb
},
props: {
title: {
type: [String, Boolean],
default: true,
required: false
},
logo: {
type: String,
default: '',
required: false
},
avatar: {
type: String,
default: '',
required: false
}
},
data () {
return {}
}
}
</script>
<style lang="less" scoped>
.page-header {
background: #fff;
padding: 16px 32px 0;
border-bottom: 1px solid #e8e8e8;
.breadcrumb {
margin-bottom: 16px;
}
.detail {
display: flex;
/*margin-bottom: 16px;*/
.avatar {
flex: 0 1 72px;
margin: 0 24px 8px 0;
& > span {
border-radius: 72px;
display: block;
width: 72px;
height: 72px;
}
}
.main {
width: 100%;
flex: 0 1 auto;
.row {
display: flex;
width: 100%;
.avatar {
margin-bottom: 16px;
}
}
.title {
font-size: 20px;
font-weight: 500;
font-size: 20px;
line-height: 28px;
font-weight: 500;
color: rgba(0, 0, 0, 0.85);
margin-bottom: 16px;
flex: auto;
}
.logo {
width: 28px;
height: 28px;
border-radius: 4px;
margin-right: 16px;
}
.content,
.headerContent {
flex: auto;
color: rgba(0, 0, 0, 0.45);
line-height: 22px;
.link {
margin-top: 16px;
line-height: 24px;
a {
font-size: 14px;
margin-right: 32px;
}
}
}
.extra {
flex: 0 1 auto;
margin-left: 88px;
min-width: 242px;
text-align: right;
}
.action {
margin-left: 56px;
min-width: 266px;
flex: 0 1 auto;
text-align: right;
&:empty {
display: none;
}
}
}
}
}
.mobile .page-header {
.main {
.row {
flex-wrap: wrap;
.avatar {
flex: 0 1 25%;
margin: 0 2% 8px 0;
}
.content,
.headerContent {
flex: 0 1 70%;
.link {
margin-top: 16px;
line-height: 24px;
a {
font-size: 14px;
margin-right: 10px;
}
}
}
.extra {
flex: 1 1 auto;
margin-left: 0;
min-width: 0;
text-align: right;
}
.action {
margin-left: unset;
min-width: 266px;
flex: 0 1 auto;
text-align: left;
margin-bottom: 12px;
&:empty {
display: none;
}
}
}
}
}
</style>

View File

@ -0,0 +1,2 @@
import PageHeader from './PageHeader'
export default PageHeader

View File

@ -0,0 +1,102 @@
<template>
<a-drawer :visible="visible" title="修改密码" :width="720" @close="onCancel">
<a-form-model ref="ruleForm" :model="form" :rules="rules" :label-col="labelCol" :wrapper-col="wrapperCol">
<a-row>
<a-col :span="24">
<a-form-model-item has-feedback label="密码" prop="pass">
<a-input v-model="form.pass" type="password" autocomplete="off" />
</a-form-model-item>
</a-col>
</a-row>
<a-row>
<a-col :span="24">
<a-form-model-item has-feedback label="确认密码" prop="checkPass">
<a-input v-model="form.checkPass" type="password" autocomplete="off" />
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
<div class="draw-button-container align-center">
<a-button @click="onCancel">取消</a-button>
<a-button type="primary" @click="onSubmit" :loading="loading">保存</a-button>
</div>
</a-drawer>
</template>
<script>
import { userPasswordSetById } from '@/api/security/user'
export default {
name: 'PasswordForm',
data () {
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('请输入密码'))
} else {
if (this.form.checkPass !== '') {
this.$refs.ruleForm.validateField('checkPass')
}
callback()
}
}
const validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('请确认密码'))
} else if (value !== this.form.pass) {
callback(new Error('两次密码不匹配'))
} else {
callback()
}
}
return {
visible: false,
labelCol: { span: 4 },
wrapperCol: { span: 16 },
form: {
pass: '',
checkPass: ''
},
rules: {
pass: [{ validator: validatePass, trigger: 'change' }],
checkPass: [{ validator: validatePass2, trigger: 'change' }]
},
loading: false,
userId: null
}
},
methods: {
show (id) {
this.userId = id
this.visible = true
},
onSubmit (e) {
if (this.loading) {
return false
}
this.loading = true
this.$refs.ruleForm.validate(valid => {
if (valid) {
userPasswordSetById({
newPassword: this.form.pass,
userId: this.userId
}).then(data => {
this.onCancel()
}).finally(() => {
this.loading = false
})
} else {
this.loading = false
return false
}
})
},
onCancel () {
this.$refs.ruleForm.resetFields()
this.visible = false
},
onReset () {
this.$refs.ruleForm.resetFields()
}
}
}
</script>

View File

@ -0,0 +1,109 @@
<template>
<div class="result">
<div>
<a-icon :class="{ 'icon': true, [`${type}`]: true }" :type="localIsSuccess ? 'check-circle' : 'close-circle'"/>
</div>
<div class="title">
<slot name="title">
{{ title }}
</slot>
</div>
<div class="description">
<slot name="description">
{{ description }}
</slot>
</div>
<div class="extra" v-if="$slots.default">
<slot></slot>
</div>
<div class="action" v-if="$slots.action">
<slot name="action"></slot>
</div>
</div>
</template>
<script>
const resultEnum = ['success', 'error']
export default {
name: 'Result',
props: {
/** @Deprecated */
isSuccess: {
type: Boolean,
default: false
},
type: {
type: String,
default: resultEnum[0],
validator (val) {
return (val) => resultEnum.includes(val)
}
},
title: {
type: String,
default: ''
},
description: {
type: String,
default: ''
}
},
computed: {
localIsSuccess: function () {
return this.type === resultEnum[0]
}
}
}
</script>
<style lang="less" scoped>
.result {
text-align: center;
width: 72%;
margin: 0 auto;
padding: 24px 0 8px;
.icon {
font-size: 72px;
line-height: 72px;
margin-bottom: 24px;
}
.success {
color: #52c41a;
}
.error {
color: red;
}
.title {
font-size: 24px;
color: rgba(0, 0, 0, .85);
font-weight: 500;
line-height: 32px;
margin-bottom: 16px;
}
.description {
font-size: 14px;
line-height: 22px;
color: rgba(0, 0, 0, 0.45);
margin-bottom: 24px;
}
.extra {
background: #fafafa;
padding: 24px 40px;
border-radius: 2px;
text-align: left;
}
.action {
margin-top: 32px;
}
}
.mobile {
.result {
width: 100%;
margin: 0 auto;
padding: unset;
}
}
</style>

View File

@ -0,0 +1,2 @@
import Result from './Result.vue'
export default Result

View File

@ -4,19 +4,15 @@ import { Icon, Menu, Dropdown } from 'ant-design-vue'
import { i18nRender } from '@/locales' import { i18nRender } from '@/locales'
import i18nMixin from '@/store/i18n-mixin' import i18nMixin from '@/store/i18n-mixin'
const locales = ['zh-CN', 'zh-TW', 'en-US', 'pt-BR'] const locales = ['zh-CN', 'en-US']
const languageLabels = { const languageLabels = {
'zh-CN': '简体中文', 'zh-CN': '简体中文',
'zh-TW': '繁体中文', 'en-US': 'English'
'en-US': 'English',
'pt-BR': 'Português'
} }
// eslint-disable-next-line // eslint-disable-next-line
const languageIcons = { const languageIcons = {
'zh-CN': '🇨🇳', 'zh-CN': '🇨🇳',
'zh-TW': '🇭🇰', 'en-US': '🇺🇸'
'en-US': '🇺🇸',
'pt-BR': '🇧🇷'
} }
const SelectLang = { const SelectLang = {

View File

@ -176,6 +176,7 @@ import config from '@/config/defaultSettings'
import { updateTheme, updateColorWeak, colorList } from './settingConfig' import { updateTheme, updateColorWeak, colorList } from './settingConfig'
export default { export default {
name: 'SettingDrawer',
components: { components: {
SettingItem SettingItem
}, },
@ -269,22 +270,17 @@ export default {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.setting-drawer-index-content { .setting-drawer-index-content {
.setting-drawer-index-blockChecbox { .setting-drawer-index-blockChecbox {
display: flex; display: flex;
.setting-drawer-index-item { .setting-drawer-index-item {
margin-right: 16px; margin-right: 16px;
position: relative; position: relative;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
img { img {
width: 48px; width: 48px;
} }
.setting-drawer-index-selectIcon { .setting-drawer-index-selectIcon {
position: absolute; position: absolute;
top: 0; top: 0;
@ -311,13 +307,11 @@ export default {
text-align: center; text-align: center;
color: #fff; color: #fff;
font-weight: 700; font-weight: 700;
i { i {
font-size: 14px; font-size: 14px;
} }
} }
} }
.setting-drawer-index-handle { .setting-drawer-index-handle {
position: absolute; position: absolute;
top: 240px; top: 240px;
@ -334,7 +328,6 @@ export default {
text-align: center; text-align: center;
font-size: 16px; font-size: 16px;
border-radius: 4px 0 0 4px; border-radius: 4px 0 0 4px;
i { i {
color: rgb(255, 255, 255); color: rgb(255, 255, 255);
font-size: 20px; font-size: 20px;

View File

@ -31,6 +31,7 @@ const colorList = [
] ]
const updateTheme = newPrimaryColor => { const updateTheme = newPrimaryColor => {
console.log('正在切换主题!')
const hideMessage = message.loading('正在切换主题!', 0) const hideMessage = message.loading('正在切换主题!', 0)
themeColor.changeColor(newPrimaryColor).finally(() => { themeColor.changeColor(newPrimaryColor).finally(() => {
setTimeout(() => { setTimeout(() => {

View File

@ -16,7 +16,8 @@ export default {
var options = { var options = {
newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors` newColors: this.getAntdSerials(newColor), // new colors array, one-to-one corresponde with `matchColors`
changeUrl (cssUrl) { changeUrl (cssUrl) {
return `/${cssUrl}` // while router is not `hash` mode, it needs absolute path console.log('cssUrl', process.env.VUE_APP_PUBLIC_PATH + `/${cssUrl}`)
return process.env.VUE_APP_PUBLIC_PATH + `/${cssUrl}` // while router is not `hash` mode, it needs absolute path
} }
} }
return client.changer.changeColor(options, Promise) return client.changer.changeColor(options, Promise)

View File

@ -5,13 +5,14 @@ export default {
data () { data () {
return { return {
needTotalList: [], needTotalList: [],
selectedRows: [], selectedRows: [],
selectedRowKeys: [], selectedRowKeys: [],
localLoading: false, localLoading: false,
localDataSource: [], localDataSource: [],
localPagination: Object.assign({}, this.pagination) localPagination: Object.assign({
showQuickJumper: true,
showTotal: total => `${total}`
}, this.pagination)
} }
}, },
props: Object.assign({}, T.props, { props: Object.assign({}, T.props, {
@ -39,12 +40,6 @@ export default {
type: String, type: String,
default: 'default' default: 'default'
}, },
/**
* alert: {
* show: true,
* clear: Function
* }
*/
alert: { alert: {
type: [Object, Boolean], type: [Object, Boolean],
default: null default: null
@ -62,15 +57,6 @@ export default {
type: String | Boolean, type: String | Boolean,
default: 'auto' default: 'auto'
}, },
/**
* enable page URI mode
*
* e.g:
* /users/1
* /users/2
* /users/3?queryParam=test
* ...
*/
pageURI: { pageURI: {
type: Boolean, type: Boolean,
default: false default: false
@ -85,7 +71,6 @@ export default {
pageNo: val pageNo: val
}) })
}) })
// change pagination, reset total data
this.needTotalList = this.initTotalList(this.columns) this.needTotalList = this.initTotalList(this.columns)
this.selectedRowKeys = [] this.selectedRowKeys = []
this.selectedRows = [] this.selectedRows = []
@ -138,7 +123,7 @@ export default {
loadData (pagination, filters, sorter) { loadData (pagination, filters, sorter) {
this.localLoading = true this.localLoading = true
const parameter = Object.assign({ const parameter = Object.assign({
pageNo: (pagination && pagination.current) || pageIndex: (pagination && pagination.current) ||
this.showPagination && this.localPagination.current || this.pageNum, this.showPagination && this.localPagination.current || this.pageNum,
pageSize: (pagination && pagination.pageSize) || pageSize: (pagination && pagination.pageSize) ||
this.showPagination && this.localPagination.pageSize || this.pageSize this.showPagination && this.localPagination.pageSize || this.pageSize
@ -158,29 +143,21 @@ export default {
if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') { if ((typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') {
result.then(r => { result.then(r => {
this.localPagination = this.showPagination && Object.assign({}, this.localPagination, { this.localPagination = this.showPagination && Object.assign({}, this.localPagination, {
current: r.pageNo, // 返回结果中的当前分页数 current: this.pageSize, // 返回结果中的当前分页数
total: r.totalCount, // 返回结果中的总记录数 total: r.total, // 返回结果中的总记录数
showSizeChanger: this.showSizeChanger, showSizeChanger: this.showSizeChanger,
pageSize: (pagination && pagination.pageSize) || pageSize: (pagination && pagination.pageSize) ||
this.localPagination.pageSize this.localPagination.pageSize
}) || false }) || false
// 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页 // 为防止删除数据后导致页面当前页面数据长度为 0 ,自动翻页到上一页
if (r.data.length === 0 && this.showPagination && this.localPagination.current > 1) { if (r.rows.length === 0 && this.showPagination && this.localPagination.current > 1) {
this.localPagination.current-- this.localPagination.current--
this.loadData() this.loadData()
return return
} }
this.localDataSource = r.rows // 返回结果中的数组数据
// 这里用于判断接口是否有返回 r.totalCount 且 this.showPagination = true 且 pageNo 和 pageSize 存在 且 totalCount 小于等于 pageNo * pageSize 的大小 this.localLoading = false
// 当情况满足时,表示数据不满足分页大小,关闭 table 分页功能 }, () => {
try {
if ((['auto', true].includes(this.showPagination) && r.totalCount <= (r.pageNo * this.localPagination.pageSize))) {
this.localPagination.hideOnSinglePage = true
}
} catch (e) {
this.localPagination = false
}
this.localDataSource = r.data // 返回结果中的数组数据
this.localLoading = false this.localLoading = false
}) })
} }

515
src/components/global.less Normal file
View File

@ -0,0 +1,515 @@
@import './index.less';
body {
}
#app {
height: 100%;
&.colorWeak {
filter: invert(80%);
}
&.userLayout {
overflow: auto;
}
}
.layout.ant-layout {
height: auto;
overflow-x: hidden;
&.mobile,
&.tablet {
.ant-layout-content {
.content {
margin: 24px 0 0;
}
}
/**
* ant-table-wrapper
* 覆盖的表格手机模式样式,如果想修改在手机上表格最低宽度,可以在这里改动
*/
.ant-table-wrapper {
.ant-table-content {
overflow-y: auto;
}
.ant-table-body {
min-width: 800px;
}
}
.topmenu {
/* 必须为 topmenu 才能启用流式布局 */
&.content-width-Fluid {
.header-index-wide {
margin-left: 0;
}
}
}
}
&.mobile {
.sidemenu {
.ant-header-fixedHeader {
&.ant-header-side-opened,
&.ant-header-side-closed {
width: 100%;
}
}
}
}
&.ant-layout-has-sider {
flex-direction: row;
}
.trigger {
font-size: 20px;
line-height: 64px;
padding: 0 24px;
cursor: pointer;
transition: color 0.3s;
&:hover {
background: rgba(0, 0, 0, 0.025);
}
}
.topmenu {
.ant-header-fixedHeader {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: 100%;
transition: width 0.2s;
&.ant-header-side-opened {
width: 100%;
}
&.ant-header-side-closed {
width: 100%;
}
}
/* 必须为 topmenu 才能启用流式布局 */
&.content-width-Fluid {
.header-index-wide {
max-width: unset;
.header-index-left {
flex: 1 1 1000px;
.logo{
margin-left: 25px;
}
.ant-menu.ant-menu-horizontal{
max-width: calc(100vw - 190px - 238px - 25px);
flex: 1 1 calc(100vw - 190px - 238px - 25px);
}
}
.header-index-right{
margin-right:25px;
}
}
.page-header-index-wide {
max-width: unset;
}
}
}
.sidemenu {
.ant-header-fixedHeader {
position: fixed;
top: 0;
right: 0;
z-index: 9;
width: 100%;
transition: width 0.2s;
&.ant-header-side-opened {
width: calc(100% - 256px);
}
&.ant-header-side-closed {
width: calc(100% - 80px);
}
}
}
.header {
height: 64px;
padding: 0 12px 0 0;
background: #fff;
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
position: relative;
}
.header,
.top-nav-header-index {
.user-wrapper {
float: right;
height: 100%;
.action {
cursor: pointer;
padding: 0 12px;
display: inline-block;
transition: all 0.3s;
height: 100%;
color: rgba(0, 0, 0, 0.65);
&:hover {
background: rgba(0, 0, 0, 0.025);
}
.avatar {
margin: 20px 8px 20px 0;
color: #1890ff;
background: hsla(0, 0%, 100%, 0.85);
vertical-align: middle;
}
.icon {
font-size: 16px;
padding: 4px;
}
}
}
&.dark {
.user-wrapper {
.action {
color: rgba(255, 255, 255, 0.85);
a {
color: rgba(255, 255, 255, 0.85);
}
&:hover {
background: rgba(255, 255, 255, 0.16);
}
}
}
}
}
&.mobile,
&.tablet {
.top-nav-header-index {
.header-index-wide {
.header-index-left {
.trigger {
color: rgba(255, 255, 255, 0.85);
padding: 0 12px;
}
.logo.top-nav-header {
flex: 0 0 56px;
text-align: center;
line-height: 58px;
h1 {
display: none;
}
}
}
}
&.light {
.header-index-wide {
.header-index-left {
.trigger {
color: rgba(0, 0, 0, 0.65);
}
}
}
//
}
}
}
&.tablet {
// overflow: hidden; text-overflow:ellipsis; white-space: nowrap;
.top-nav-header-index {
.header-index-wide {
.header-index-left {
.logo > a {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.ant-menu.ant-menu-horizontal {
flex: 1 1 auto;
white-space: normal;
}
}
}
}
.top-nav-header-index {
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
position: relative;
transition: background 0.3s, width 0.2s;
.header-index-wide {
max-width: 1200px;
margin: auto;
padding-left: 0;
display: flex;
height: 64px;
.ant-menu.ant-menu-horizontal {
max-width: 835px;
flex: 0 1 835px;
border: none;
height: 64px;
line-height: 64px;
}
.header-index-left {
flex: 0 1 1000px;
display: flex;
.logo.top-nav-header {
flex: 0 0 165px;
width: 165px;
height: 64px;
position: relative;
line-height: 64px;
transition: all 0.3s;
overflow: hidden;
img,
svg {
display: inline-block;
vertical-align: middle;
height: 32px;
width: 32px;
}
h1 {
color: #fff;
display: inline-block;
vertical-align: top;
font-size: 16px;
margin: 0 0 0 12px;
font-weight: 400;
}
}
}
.header-index-right {
flex: 0 0 238px;
align-self: flex-end;
height: 64px;
overflow: hidden;
.content-box {
float: right;
.action {
max-width: 140px;
overflow: hidden;
text-overflow:ellipsis;
white-space:nowrap;
}
}
}
}
&.light {
background-color: #fff;
.header-index-wide {
.header-index-left {
.logo {
h1 {
color: #002140;
}
}
}
}
}
}
// 内容区
.layout-content {
margin: 24px 24px 0px;
height: 100%;
height: 64px;
padding: 0 12px 0 0;
}
// footer
.ant-layout-footer {
padding: 0;
}
}
.topmenu {
.page-header-index-wide {
max-width: 1200px;
margin: 0 auto;
}
}
// drawer-sider 自定义
.ant-drawer.drawer-sider {
.sider {
box-shadow: none;
}
&.dark {
.ant-drawer-content {
background-color: rgb(0, 21, 41);
}
}
&.light {
box-shadow: none;
.ant-drawer-content {
background-color: #fff;
}
}
.ant-drawer-body {
padding: 0;
}
}
// 菜单样式
.sider {
box-shadow: 2px 0 6px rgba(0, 21, 41, 0.35);
position: relative;
z-index: @ant-global-sider-zindex;
min-height: 100vh;
.ant-layout-sider-children {
overflow-y: hidden;
&:hover {
overflow-y: auto;
}
}
&.ant-fixed-sidemenu {
position: fixed;
height: 100%;
}
.logo {
position: relative;
height: 64px;
padding-left: 24px;
overflow: hidden;
line-height: 64px;
background: #002140;
transition: all .3s;
img,
svg,
h1 {
display: inline-block;
vertical-align: middle;
}
img,
svg {
height: 32px;
width: 32px;
}
h1 {
color: #fff;
font-size: 20px;
margin: 0 0 0 12px;
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
font-weight: 600;
vertical-align: middle;
}
}
&.light {
background-color: #fff;
box-shadow: 2px 0px 8px 0px rgba(29, 35, 41, 0.05);
.logo {
background: #fff;
box-shadow: 1px 1px 0px 0px #e8e8e8;
h1 {
color: unset;
}
}
.ant-menu-light {
border-right-color: transparent;
}
}
}
// 外置的样式控制
.user-dropdown-menu {
span {
user-select: none;
}
}
.user-dropdown-menu-wrapper.ant-dropdown-menu {
padding: 4px 0;
.ant-dropdown-menu-item {
width: 160px;
}
.ant-dropdown-menu-item > .anticon:first-child,
.ant-dropdown-menu-item > a > .anticon:first-child,
.ant-dropdown-menu-submenu-title > .anticon:first-child .ant-dropdown-menu-submenu-title > a > .anticon:first-child {
min-width: 12px;
margin-right: 8px;
}
}
// 数据列表 样式
.table-alert {
margin-bottom: 16px;
}
.table-page-search-wrapper {
.ant-form-inline {
.ant-form-item {
display: flex;
margin-bottom: 24px;
margin-right: 0;
.ant-form-item-control-wrapper {
flex: 1 1;
display: inline-block;
vertical-align: middle;
}
> .ant-form-item-label {
line-height: 32px;
padding-right: 8px;
width: auto;
}
.ant-form-item-control {
height: 32px;
line-height: 32px;
}
}
}
.table-page-search-submitButtons {
display: block;
margin-bottom: 24px;
white-space: nowrap;
}
}
.content {
.table-operator {
margin-bottom: 18px;
button {
margin-right: 8px;
}
}
}

View File

@ -16,7 +16,6 @@ import AvatarList from '@/components/AvatarList'
import Ellipsis from '@/components/Ellipsis' import Ellipsis from '@/components/Ellipsis'
import FooterToolbar from '@/components/FooterToolbar' import FooterToolbar from '@/components/FooterToolbar'
import NumberInfo from '@/components/NumberInfo' import NumberInfo from '@/components/NumberInfo'
import Tree from '@/components/Tree/Tree'
import Trend from '@/components/Trend' import Trend from '@/components/Trend'
import STable from '@/components/Table' import STable from '@/components/Table'
import MultiTab from '@/components/MultiTab' import MultiTab from '@/components/MultiTab'
@ -24,8 +23,8 @@ import IconSelector from '@/components/IconSelector'
import TagSelect from '@/components/TagSelect' import TagSelect from '@/components/TagSelect'
import StandardFormRow from '@/components/StandardFormRow' import StandardFormRow from '@/components/StandardFormRow'
import ArticleListContent from '@/components/ArticleListContent' import ArticleListContent from '@/components/ArticleListContent'
import Dialog from '@/components/Dialog' import Dialog from '@/components/Dialog'
import ImageUpload from '@/components/ImageUpload'
export { export {
AvatarList, AvatarList,
@ -44,13 +43,12 @@ export {
Ellipsis, Ellipsis,
FooterToolbar, FooterToolbar,
NumberInfo, NumberInfo,
Tree,
STable, STable,
MultiTab, MultiTab,
IconSelector, IconSelector,
TagSelect, TagSelect,
StandardFormRow, StandardFormRow,
ArticleListContent, ArticleListContent,
Dialog,
Dialog ImageUpload
} }

View File

@ -0,0 +1,42 @@
<template>
<a-breadcrumb class="breadcrumb">
<a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">
<router-link
v-if="item.name != name && index != 1"
:to="{ path: item.path === '' ? '/' : item.path }"
>{{ item.meta.title }}</router-link>
<span v-else>{{ item.meta.title }}</span>
</a-breadcrumb-item>
</a-breadcrumb>
</template>
<script>
export default {
data () {
return {
name: '',
breadList: []
}
},
created () {
this.getBreadcrumb()
},
methods: {
getBreadcrumb () {
this.breadList = []
this.name = this.$route.name
this.$route.matched.forEach(item => {
this.breadList.push(item)
})
}
},
watch: {
$route () {
this.getBreadcrumb()
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,5 @@
<script>
/* WARNING: 兼容老引入,请勿继续使用 */
import DescriptionList from '@/components/DescriptionList'
export default DescriptionList
</script>

View File

@ -0,0 +1,67 @@
<template>
<div class="head-info" :class="center && 'center'">
<span>{{ title }}</span>
<p>{{ content }}</p>
<em v-if="bordered"/>
</div>
</template>
<script>
export default {
name: 'HeadInfo',
props: {
title: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
bordered: {
type: Boolean,
default: false
},
center: {
type: Boolean,
default: true
}
}
}
</script>
<style lang="less" scoped>
.head-info {
position: relative;
text-align: left;
padding: 0 32px 0 0;
min-width: 125px;
&.center {
text-align: center;
padding: 0 32px;
}
span {
color: rgba(0, 0, 0, .45);
display: inline-block;
font-size: 14px;
line-height: 22px;
margin-bottom: 4px;
}
p {
color: rgba(0, 0, 0, .85);
font-size: 24px;
line-height: 32px;
margin: 0;
}
em {
background-color: #e8e8e8;
position: absolute;
height: 56px;
width: 1px;
top: 0;
right: 0;
}
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<a-dropdown>
<span class="action global-lang">
<a-icon type="global" style="font-size: 16px"/>
</span>
<a-menu slot="overlay" style="width: 150px;" @click="SwitchLang">
<a-menu-item key="zh-CN">
<a rel="noopener noreferrer">
<span role="img" aria-label="简体中文">🇨🇳</span> 简体中文
</a>
</a-menu-item>
<a-menu-item key="zh-TW">
<a rel="noopener noreferrer">
<span role="img" aria-label="繁体中文">🇭🇰</span> 繁体中文
</a>
</a-menu-item>
<a-menu-item key="en-US">
<a rel="noopener noreferrer">
<span role="img" aria-label="English">🇬🇧</span> English
</a>
</a-menu-item>
<a-menu-item key="pt-BR">
<a rel="noopener noreferrer">
<span role="img" aria-label="Português">🇧🇷</span> Português
</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</template>
<script>
// import { mixin as langMixin } from '@/store/i18n-mixin'
export default {
name: 'LangSelect',
// mixins: [langMixin],
data () {
return {}
},
methods: {
// SwitchLang (row) {
// this.setLang(row.key)
// }
}
}
</script>

View File

@ -0,0 +1,31 @@
<template>
<div class="logo">
<router-link :to="{name:'dashboard'}">
<LogoSvg alt="logo" />
<h1 v-if="showTitle">{{ title }}</h1>
</router-link>
</div>
</template>
<script>
import LogoSvg from '@/assets/logo.svg?inline'
export default {
name: 'Logo',
components: {
LogoSvg
},
props: {
title: {
type: String,
default: 'AntD',
required: false
},
showTitle: {
type: Boolean,
default: true,
required: false
}
}
}
</script>

View File

@ -0,0 +1,81 @@
<template>
<div class="user-wrapper">
<div class="content-box">
<a href="https://pro.loacg.com/docs/getting-started" target="_blank">
<span class="action">
<a-icon type="question-circle-o"></a-icon>
</span>
</a>
<notice-icon class="action"/>
<a-dropdown>
<span class="action ant-dropdown-link user-dropdown-menu">
<a-avatar class="avatar" size="small" :src="avatar"/>
<span>{{ nickname }}</span>
</span>
<a-menu slot="overlay" class="user-dropdown-menu-wrapper">
<a-menu-item key="0">
<router-link :to="{ name: 'center' }">
<a-icon type="user"/>
<span>个人中心</span>
</router-link>
</a-menu-item>
<a-menu-item key="1">
<router-link :to="{ name: 'settings' }">
<a-icon type="setting"/>
<span>账户设置</span>
</router-link>
</a-menu-item>
<a-menu-item key="2" disabled>
<a-icon type="setting"/>
<span>测试</span>
</a-menu-item>
<a-menu-divider/>
<a-menu-item key="3">
<a href="javascript:;" @click="handleLogout">
<a-icon type="logout"/>
<span>退出登录</span>
</a>
</a-menu-item>
</a-menu>
</a-dropdown>
</div>
</div>
</template>
<script>
import NoticeIcon from '@/components/NoticeIcon'
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'UserMenu',
components: {
NoticeIcon
},
computed: {
...mapGetters(['nickname', 'avatar'])
},
methods: {
...mapActions(['Logout']),
handleLogout () {
this.$confirm({
title: '提示',
content: '真的要注销登录吗 ?',
onOk: () => {
return this.Logout({}).then(() => {
setTimeout(() => {
window.location.reload()
}, 16)
}).catch(err => {
this.$message.error({
title: '错误',
description: err.message
})
})
},
onCancel () {
}
})
}
}
}
</script>

View File

View File

@ -14,8 +14,8 @@
export default { export default {
navTheme: 'dark', // theme for nav menu navTheme: 'dark', // theme for nav menu
primaryColor: '#52C41A', // primary color of ant design primaryColor: '#5555ff', // primary color of ant design
layout: 'sidemenu', // nav menu position: `sidemenu` or `topmenu` layout: 'topmenu', // nav menu position: `sidemenu` or `topmenu`
contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
fixedHeader: false, // sticky header fixedHeader: false, // sticky header
fixSiderbar: false, // sticky siderbar fixSiderbar: false, // sticky siderbar
@ -23,7 +23,7 @@ export default {
menu: { menu: {
locale: true locale: true
}, },
title: 'Ant Design Pro', title: '系统后台',
pwa: false, pwa: false,
iconfontUrl: '', iconfontUrl: '',
production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true' production: process.env.NODE_ENV === 'production' && process.env.VUE_APP_PREVIEW !== 'true'

Some files were not shown because too many files have changed in this diff Show More