├── .env.development
├── .env.production
├── .eslintrc.js
├── .gitignore
├── README.md
├── babel.config.js
├── network_disk.sql
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── server
├── .gitignore
├── app.js
├── bin
│ └── www
├── db
│ ├── createTable
│ │ ├── createUserList.js
│ │ └── cteateFileList.js
│ ├── fileList.js
│ ├── index.js
│ └── user_list.js
├── model
│ ├── Result.js
│ └── file.js
├── package-lock.json
├── package.json
├── public
│ ├── images
│ │ └── 新建文本文档.txt
│ └── stylesheets
│ │ └── style.css
├── routes
│ ├── file.js
│ ├── index.js
│ ├── jwt.js
│ ├── upload.js
│ └── users.js
├── servers
│ ├── dbOperation.js
│ ├── file.js
│ └── user.js
├── tool
│ ├── constant.js
│ ├── env.js
│ ├── file.js
│ ├── index.js
│ ├── public.js
│ ├── schedule.js
│ └── send.js
└── views
│ ├── error.jade
│ ├── index.jade
│ └── layout.jade
├── src
├── App.vue
├── api
│ ├── file.js
│ └── user.js
├── assets
│ ├── font
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.woff2
│ ├── images
│ │ ├── 404.png
│ │ ├── AVI.png
│ │ ├── WORD.png
│ │ ├── excel.png
│ │ ├── img.png
│ │ ├── mp3.png
│ │ ├── no-data.png
│ │ ├── ppt.png
│ │ ├── qita.png
│ │ └── zip.png
│ ├── reset.css
│ └── scss
│ │ └── index.scss
├── components
│ ├── DownloadList
│ │ ├── DownloadList.vue
│ │ └── cop.vue
│ ├── Mark
│ │ └── Mark.vue
│ ├── NoData
│ │ └── NoData.vue
│ ├── Upload
│ │ └── Upload.vue
│ ├── funcTool
│ │ └── funcTool.vue
│ └── progress
│ │ └── progress.vue
├── electron
│ ├── icon
│ │ └── logo.png
│ ├── index.js
│ └── lib
│ │ └── ipcMain.js
├── main.js
├── pages
│ ├── 404
│ │ └── 404.vue
│ ├── CompleteTransfer
│ │ └── CompleteTransfer.vue
│ ├── Hide
│ │ └── Hide.vue
│ ├── Home
│ │ ├── Home.vue
│ │ └── components
│ │ │ ├── FileButton.vue
│ │ │ ├── FunctionColumn.vue
│ │ │ └── fileUpload.vue
│ ├── Index
│ │ ├── Index.vue
│ │ └── component
│ │ │ ├── AppMain
│ │ │ ├── AppMain.vue
│ │ │ └── component
│ │ │ │ └── HistoricalRecords.vue
│ │ │ ├── IndexLeft
│ │ │ └── IndexLeft.vue
│ │ │ └── IndexTop
│ │ │ └── IndexTop.vue
│ ├── Login
│ │ └── Login.vue
│ ├── RecycleBin
│ │ └── RecycleBin.vue
│ ├── Redirect
│ │ └── index.vue
│ ├── Search
│ │ └── Search.vue
│ ├── Share
│ │ └── Share.vue
│ ├── TransferList
│ │ ├── TransferList.vue
│ │ └── components
│ │ │ └── uploadList.vue
│ └── applicationAccount
│ │ └── applicationAccount.vue
├── permission.js
├── router
│ ├── _import_development.js
│ ├── _import_production.js
│ └── index.js
├── store
│ ├── getters.js
│ ├── index.js
│ └── modules
│ │ ├── file.js
│ │ ├── history.js
│ │ ├── navList.js
│ │ ├── upload.js
│ │ └── user.js
└── utils
│ ├── ElementUI.js
│ ├── FileTool.js
│ ├── config.js
│ ├── publicTool.js
│ ├── request.js
│ ├── tokne.js
│ └── util.js
├── vue.config.js
└── yarn.lock
/.env.development:
--------------------------------------------------------------------------------
1 |
2 | # just a flag
3 | NODE_ENV = 'development'
4 |
5 | # base api
6 | # VUE_APP_BASE_API = '/dev-api'
7 |
8 |
9 | VUE_APP_BASE_API = 'http://192.168.1.64:3000'
10 |
11 |
12 | # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,
13 | # to control whether the babel-plugin-dynamic-import-node plugin is enabled.
14 | # It only does one thing by converting all import() to require().
15 | # This configuration can significantly increase the speed of hot updates,
16 | # when you have a large number of pages.
17 | # Detail: https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/babel-preset-app/index.js
18 |
19 | VUE_CLI_BABEL_TRANSPILE_MODULES = true
20 |
--------------------------------------------------------------------------------
/.env.production:
--------------------------------------------------------------------------------
1 | # just a flag
2 | NODE_ENV = 'production'
3 |
4 | # base api
5 | # VUE_APP_BASE_API = '/prod-api'
6 |
7 | VUE_APP_BASE_API = 'http://192.168.1.64:3000'
8 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parserOptions: {
4 | parser: 'babel-eslint',
5 | sourceType: 'module'
6 | },
7 | env: {
8 | browser: true,
9 | node: true,
10 | es6: true,
11 | },
12 | extends: ['plugin:vue/recommended', 'eslint:recommended'],
13 |
14 | // add your custom rules here
15 | //it is base on https://github.com/vuejs/eslint-config-vue
16 | rules: {
17 | "vue/max-attributes-per-line": [2, {
18 | "singleline": 10,
19 | "multiline": {
20 | "max": 1,
21 | "allowFirstLine": false
22 | }
23 | }],
24 | "vue/singleline-html-element-content-newline": "off",
25 | "vue/multiline-html-element-content-newline":"off",
26 | "vue/name-property-casing": ["error", "PascalCase"],
27 | "vue/no-v-html": "off",
28 | 'accessor-pairs': 2,
29 | 'arrow-spacing': [2, {
30 | 'before': true,
31 | 'after': true
32 | }],
33 | 'block-spacing': [2, 'always'],
34 | 'brace-style': [2, '1tbs', {
35 | 'allowSingleLine': true
36 | }],
37 | 'camelcase': [0, {
38 | 'properties': 'always'
39 | }],
40 | 'comma-dangle': [2, 'never'],
41 | 'comma-spacing': [2, {
42 | 'before': false,
43 | 'after': true
44 | }],
45 | 'comma-style': [2, 'last'],
46 | 'constructor-super': 2,
47 | 'curly': [2, 'multi-line'],
48 | 'dot-location': [2, 'property'],
49 | 'eol-last': 2,
50 | 'eqeqeq': ["error", "always", {"null": "ignore"}],
51 | 'generator-star-spacing': [2, {
52 | 'before': true,
53 | 'after': true
54 | }],
55 | 'handle-callback-err': [2, '^(err|error)$'],
56 | 'indent': [2, 2, {
57 | 'SwitchCase': 1
58 | }],
59 | 'jsx-quotes': [2, 'prefer-single'],
60 | 'key-spacing': [2, {
61 | 'beforeColon': false,
62 | 'afterColon': true
63 | }],
64 | 'keyword-spacing': [2, {
65 | 'before': true,
66 | 'after': true
67 | }],
68 | 'new-cap': [2, {
69 | 'newIsCap': true,
70 | 'capIsNew': false
71 | }],
72 | 'new-parens': 2,
73 | 'no-array-constructor': 2,
74 | 'no-caller': 2,
75 | 'no-console': 'off',
76 | 'no-class-assign': 2,
77 | 'no-cond-assign': 2,
78 | 'no-const-assign': 2,
79 | 'no-control-regex': 0,
80 | 'no-delete-var': 2,
81 | 'no-dupe-args': 2,
82 | 'no-dupe-class-members': 2,
83 | 'no-dupe-keys': 2,
84 | 'no-duplicate-case': 2,
85 | 'no-empty-character-class': 2,
86 | 'no-empty-pattern': 2,
87 | 'no-eval': 2,
88 | 'no-ex-assign': 2,
89 | 'no-extend-native': 2,
90 | 'no-extra-bind': 2,
91 | 'no-extra-boolean-cast': 2,
92 | 'no-extra-parens': [2, 'functions'],
93 | 'no-fallthrough': 2,
94 | 'no-floating-decimal': 2,
95 | 'no-func-assign': 2,
96 | 'no-implied-eval': 2,
97 | 'no-inner-declarations': [2, 'functions'],
98 | 'no-invalid-regexp': 2,
99 | 'no-irregular-whitespace': 2,
100 | 'no-iterator': 2,
101 | 'no-label-var': 2,
102 | 'no-labels': [2, {
103 | 'allowLoop': false,
104 | 'allowSwitch': false
105 | }],
106 | 'no-lone-blocks': 2,
107 | 'no-mixed-spaces-and-tabs': 2,
108 | 'no-multi-spaces': 2,
109 | 'no-multi-str': 2,
110 | 'no-multiple-empty-lines': [2, {
111 | 'max': 1
112 | }],
113 | 'no-native-reassign': 2,
114 | 'no-negated-in-lhs': 2,
115 | 'no-new-object': 2,
116 | 'no-new-require': 2,
117 | 'no-new-symbol': 2,
118 | 'no-new-wrappers': 2,
119 | 'no-obj-calls': 2,
120 | 'no-octal': 2,
121 | 'no-octal-escape': 2,
122 | 'no-path-concat': 2,
123 | 'no-proto': 2,
124 | 'no-redeclare': 2,
125 | 'no-regex-spaces': 2,
126 | 'no-return-assign': [2, 'except-parens'],
127 | 'no-self-assign': 2,
128 | 'no-self-compare': 2,
129 | 'no-sequences': 2,
130 | 'no-shadow-restricted-names': 2,
131 | 'no-spaced-func': 2,
132 | 'no-sparse-arrays': 2,
133 | 'no-this-before-super': 2,
134 | 'no-throw-literal': 2,
135 | 'no-trailing-spaces': 2,
136 | 'no-undef': 2,
137 | 'no-undef-init': 2,
138 | 'no-unexpected-multiline': 2,
139 | 'no-unmodified-loop-condition': 2,
140 | 'no-unneeded-ternary': [2, {
141 | 'defaultAssignment': false
142 | }],
143 | 'no-unreachable': 2,
144 | 'no-unsafe-finally': 2,
145 | 'no-unused-vars': [2, {
146 | 'vars': 'all',
147 | 'args': 'none'
148 | }],
149 | 'no-useless-call': 2,
150 | 'no-useless-computed-key': 2,
151 | 'no-useless-constructor': 2,
152 | 'no-useless-escape': 0,
153 | 'no-whitespace-before-property': 2,
154 | 'no-with': 2,
155 | 'one-var': [2, {
156 | 'initialized': 'never'
157 | }],
158 | 'operator-linebreak': [2, 'after', {
159 | 'overrides': {
160 | '?': 'before',
161 | ':': 'before'
162 | }
163 | }],
164 | 'padded-blocks': [2, 'never'],
165 | 'quotes': [2, 'single', {
166 | 'avoidEscape': true,
167 | 'allowTemplateLiterals': true
168 | }],
169 | 'semi': [2, 'never'],
170 | 'semi-spacing': [2, {
171 | 'before': false,
172 | 'after': true
173 | }],
174 | 'space-before-blocks': [2, 'always'],
175 | 'space-before-function-paren': [2, 'never'],
176 | 'space-in-parens': [2, 'never'],
177 | 'space-infix-ops': 2,
178 | 'space-unary-ops': [2, {
179 | 'words': true,
180 | 'nonwords': false
181 | }],
182 | 'spaced-comment': [2, 'always', {
183 | 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
184 | }],
185 | 'template-curly-spacing': [2, 'never'],
186 | 'use-isnan': 2,
187 | 'valid-typeof': 2,
188 | 'wrap-iife': [2, 'any'],
189 | 'yield-star-spacing': [2, 'both'],
190 | 'yoda': [2, 'never'],
191 | 'prefer-const': 2,
192 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
193 | 'object-curly-spacing': [2, 'always', {
194 | objectsInObjects: false
195 | }],
196 | 'array-bracket-spacing': [2, 'never']
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### 安装项目
2 | ```
3 | npm install
4 | ```
5 |
6 | ### 启动web项目
7 | ```
8 | npm run dev
9 | ```
10 |
11 | ### 启用electron
12 |
13 | ```
14 | npm run dev:exe
15 | ```
16 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | ['@vue/app', {
4 | useBuiltIns: 'entry'
5 | }],
6 | [
7 | "@babel/preset-env",
8 | {
9 | "useBuiltIns": "entry"
10 | }
11 | ]
12 | ],
13 | "plugins": [
14 | [
15 | "component",
16 | {
17 | "libraryName": "element-ui",
18 | "styleLibraryName": "theme-chalk"
19 | }
20 | ]
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/network_disk.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat Premium Data Transfer
3 |
4 | Source Server : localhost_3306
5 | Source Server Type : MySQL
6 | Source Server Version : 80021
7 | Source Host : localhost:3306
8 | Source Schema : network_disk
9 |
10 | Target Server Type : MySQL
11 | Target Server Version : 80021
12 | File Encoding : 65001
13 |
14 | Date: 27/05/2021 16:20:10
15 | */
16 |
17 | SET NAMES utf8mb4;
18 | SET FOREIGN_KEY_CHECKS = 0;
19 |
20 | -- ----------------------------
21 | -- Table structure for file_list
22 | -- ----------------------------
23 | DROP TABLE IF EXISTS `file_list`;
24 | CREATE TABLE `file_list` (
25 | `f_id` int(0) NOT NULL AUTO_INCREMENT,
26 | `f_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
27 | `f_size` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
28 | `f_dow_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
29 | `f_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
30 | `f_grouping` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
31 | `f_transfer_state` int(0) DEFAULT 0,
32 | `f_history_state` int(0) DEFAULT 0,
33 | `u_id` int(0) DEFAULT NULL,
34 | `u_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
35 | `version` bigint(0) DEFAULT NULL,
36 | `createdAt` datetime(0) NOT NULL,
37 | `updatedAt` datetime(0) NOT NULL,
38 | `deletedAt` datetime(0) DEFAULT NULL,
39 | PRIMARY KEY (`f_id`) USING BTREE,
40 | UNIQUE INDEX `f_id`(`f_id`) USING BTREE
41 | ) ENGINE = InnoDB AUTO_INCREMENT = 30 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
42 |
43 | -- ----------------------------
44 | -- Records of file_list
45 | -- ----------------------------
46 | INSERT INTO `file_list` VALUES (1, 'dkxt.rar', '106401468', 'public/upload/users/shanjianL/dkxt.rar', 'application/octet-stream', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-08-24 16:51:56', '2020-09-14 17:43:05', '2020-09-14 17:53:41');
47 | INSERT INTO `file_list` VALUES (2, 'dkxt.rar', '106401468', 'public/upload/users/shanjianL/dkxt.rar', 'application/octet-stream', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-08-25 13:12:32', '2020-09-14 16:00:39', '2020-09-15 15:58:00');
48 | INSERT INTO `file_list` VALUES (3, 'dkxt.rar', '106401468', 'public/upload/users/shanjianL/dkxt.rar', 'application/octet-stream', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-08-25 17:05:08', '2020-09-15 16:15:59', '2020-09-15 16:16:15');
49 | INSERT INTO `file_list` VALUES (4, 'Office_2010_激活工具.zip', '19062796', 'public/upload/users/shanjianL/Office_2010_激活工具.zip', 'application/x-zip-compressed', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-08-31 22:25:03', '2020-09-15 16:17:28', '2020-09-15 16:17:35');
50 | INSERT INTO `file_list` VALUES (5, 'Office_2010_激活工具.zip', '19062796', 'public/upload/users/shanjianL/Office_2010_激活工具.zip', 'application/x-zip-compressed', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-08-31 22:26:03', '2020-09-14 16:03:34', '2020-09-15 16:04:10');
51 | INSERT INTO `file_list` VALUES (6, 'hodgepodge-master.zip', '131067', 'public/upload/users/shanjianL/hodgepodge-master.zip', 'application/x-zip-compressed', 'shanjianL', 0, 0, 1, 'shanjianL', 0, '2020-09-03 14:57:28', '2020-09-03 14:57:28', '2020-09-15 16:12:17');
52 | INSERT INTO `file_list` VALUES (7, 'hodgepodge-master.zip', '131067', 'public/upload/users/shanjianL/hodgepodge-master.zip', 'application/x-zip-compressed', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-09-03 15:00:17', '2020-09-14 16:05:58', '2020-09-15 16:12:17');
53 | INSERT INTO `file_list` VALUES (8, 'download.zip', '24063', 'public/upload/users/shanjianL / shanjianL/2/5/download.zip', 'application/x-zip-compressed', 'shanjianL/2/5', 0, 0, 1, 'shanjianL', 0, '2020-09-03 15:00:58', '2020-09-03 15:00:58', NULL);
54 | INSERT INTO `file_list` VALUES (9, 'dkxt.rar', '106401468', 'public/upload/users/shanjianL/2/dkxt.rar', 'application/octet-stream', 'shanjianL/2', 0, 0, 1, 'shanjianL', 0, '2020-09-03 15:03:47', '2020-09-03 15:03:47', NULL);
55 | INSERT INTO `file_list` VALUES (10, 'Interop.QuartzTypeLib.dll', '18944', 'public/upload/users/shanjianL/2/Interop.QuartzTypeLib.dll', 'application/x-msdownload', 'shanjianL/2', 0, 0, 1, 'shanjianL', 0, '2020-09-08 11:25:58', '2020-09-08 11:25:58', NULL);
56 | INSERT INTO `file_list` VALUES (11, 'content.txt', '0', 'public/upload/users/shanjianL/content.txt', 'text/plain', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-09-15 16:20:21', '2020-09-15 16:20:28', '2020-09-15 16:20:37');
57 | INSERT INTO `file_list` VALUES (12, 'content.txt', '0', 'public/upload/users/shanjianL/content.txt', 'text/plain', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2020-09-15 16:21:10', '2020-09-15 16:21:23', '2020-09-15 16:21:28');
58 | INSERT INTO `file_list` VALUES (13, 'personalBlog.sql', '45356', 'public/upload/users/shanjianL/personalBlog.sql', 'application/octet-stream', 'shanjianL', 0, 1, 1, 'shanjianL', 0, '2021-04-22 14:25:26', '2021-04-22 14:25:43', NULL);
59 | INSERT INTO `file_list` VALUES (14, 'user.png.png', '7702', 'public/upload/users/shanjianL/user.png.png', 'image/png', 'shanjianL', 0, 0, 1, 'shanjianL', 0, '2021-05-14 13:53:35', '2021-05-14 13:53:35', NULL);
60 | INSERT INTO `file_list` VALUES (15, 'user.png.png', '7702', 'public/upload/users/tourist/user.png.png', 'image/png', 'tourist', 1, 1, 9, 'tourist', 0, '2021-05-20 16:24:18', '2021-05-27 15:22:10', '2021-05-27 15:27:52');
61 | INSERT INTO `file_list` VALUES (16, 'personalBlog.sql', '45356', 'public/upload/users/tourist/personalBlog.sql', 'application/octet-stream', 'tourist', 1, 1, 9, 'tourist', 0, '2021-05-20 16:25:58', '2021-05-27 15:29:58', '2021-05-27 15:30:03');
62 | INSERT INTO `file_list` VALUES (17, 'vue2-elm-master.zip', '13153220', 'public/upload/users/tourist/vue2-elm-master.zip', 'application/x-zip-compressed', 'tourist', 1, 1, 9, 'tourist', 0, '2021-05-21 16:12:40', '2021-05-27 15:33:48', '2021-05-27 15:33:55');
63 | INSERT INTO `file_list` VALUES (18, 'index.vue', '4793', 'public/upload/users/tourist/index.vue', 'application/octet-stream', 'tourist', 1, 1, 9, 'tourist', 0, '2021-05-21 17:03:33', '2021-05-27 15:32:27', '2021-05-27 15:32:35');
64 | INSERT INTO `file_list` VALUES (19, '新建文件夹 (21).rar', '117056', 'public/upload/users/tourist/新建文件夹 (21).rar', 'application/octet-stream', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 13:58:05', '2021-05-27 15:42:58', '2021-05-27 15:43:02');
65 | INSERT INTO `file_list` VALUES (20, 'vue-eleme-master.zip', '1096687', 'public/upload/users/tourist/vue-eleme-master.zip', 'application/x-zip-compressed', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 13:58:15', '2021-05-27 15:46:02', '2021-05-27 15:46:05');
66 | INSERT INTO `file_list` VALUES (21, 'tianlula.github.io-main.zip', '2843', 'public/upload/users/tourist/tianlula.github.io-main.zip', 'application/x-zip-compressed', 'tourist', 1, 1, 9, 'tourist', 0, '2021-05-25 15:30:15', '2021-05-27 16:15:47', '2021-05-27 16:15:52');
67 | INSERT INTO `file_list` VALUES (22, 'aoaoe-master.zip', '8348349', 'public/upload/users/tourist/aoaoe-master.zip', 'application/x-zip-compressed', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 15:32:32', '2021-05-25 15:32:32', NULL);
68 | INSERT INTO `file_list` VALUES (23, '模型评测原型_需先设计的副本.zip', '641970', 'public/upload/users/tourist/模型评测原型_需先设计的副本.zip', 'application/x-zip-compressed', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 15:47:58', '2021-05-27 15:48:04', '2021-05-27 15:48:07');
69 | INSERT INTO `file_list` VALUES (24, '3q-api.pdf', '103762', 'public/upload/users/tourist/3q-api.pdf', 'application/pdf', 'tourist', 0, 1, 9, 'tourist', 0, '2021-05-25 16:27:45', '2021-05-27 16:15:06', '2021-05-27 16:15:09');
70 | INSERT INTO `file_list` VALUES (25, 'eleme-master.zip', '755421', 'public/upload/users/tourist/eleme-master.zip', 'application/x-zip-compressed', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 16:30:23', '2021-05-25 16:30:23', NULL);
71 | INSERT INTO `file_list` VALUES (26, 'shop.rar', '1328016', 'public/upload/users/tourist/shop.rar', 'application/octet-stream', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 16:31:50', '2021-05-25 16:31:50', NULL);
72 | INSERT INTO `file_list` VALUES (27, 'l.rar', '95413', 'public/upload/users/tourist/l.rar', 'application/octet-stream', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 16:54:32', '2021-05-25 16:54:32', NULL);
73 | INSERT INTO `file_list` VALUES (28, 'l.rar', '95413', 'public/upload/users/tourist/l.rar', 'application/octet-stream', 'tourist', 0, 1, 9, 'tourist', 0, '2021-05-25 17:03:25', '2021-05-27 15:36:29', '2021-05-27 15:36:45');
74 | INSERT INTO `file_list` VALUES (29, '新建文件夹 (21).rar', '117056', 'public/upload/users/tourist/新建文件夹 (21).rar', 'application/octet-stream', 'tourist', 0, 0, 9, 'tourist', 0, '2021-05-25 17:04:30', '2021-05-25 17:04:30', NULL);
75 |
76 | -- ----------------------------
77 | -- Table structure for user_list
78 | -- ----------------------------
79 | DROP TABLE IF EXISTS `user_list`;
80 | CREATE TABLE `user_list` (
81 | `u_id` int(0) NOT NULL AUTO_INCREMENT,
82 | `u_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
83 | `u_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
84 | `u_capacity` int(0) NOT NULL DEFAULT 10,
85 | `u_password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '123456',
86 | `u_pic` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png',
87 | `version` bigint(0) DEFAULT NULL,
88 | `createdAt` datetime(0) NOT NULL,
89 | `updatedAt` datetime(0) NOT NULL,
90 | `deletedAt` datetime(0) DEFAULT NULL,
91 | `u_used_capacity` tinyint(0) DEFAULT NULL,
92 | PRIMARY KEY (`u_id`) USING BTREE,
93 | UNIQUE INDEX `u_id`(`u_id`) USING BTREE
94 | ) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
95 |
96 | -- ----------------------------
97 | -- Records of user_list
98 | -- ----------------------------
99 | INSERT INTO `user_list` VALUES (1, 'shanjianL', '272781702@qq.com', 10, '123456', 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png', 0, '2020-08-11 17:30:49', '2020-08-11 17:30:49', NULL, 0);
100 | INSERT INTO `user_list` VALUES (9, 'tourist', '769840101@qq.com', 10, '123456', 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png', 0, '2021-05-20 15:50:27', '2021-05-20 15:50:27', NULL, NULL);
101 |
102 | SET FOREIGN_KEY_CHECKS = 1;
103 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "disc",
3 | "version": "0.1.0",
4 | "private": true,
5 | "main": "./src/electron/index.js",
6 | "scripts": {
7 | "dev": "vue-cli-service serve",
8 | "dev:exe": "./node_modules/.bin/electron ./",
9 | "build": "vue-cli-service build",
10 | "build:exe": "./node_modules/.bin/electron-builder build",
11 | "lint": "vue-cli-service lint"
12 | },
13 | "dependencies": {
14 | "axios": "^0.19.2",
15 | "core-js": "^3.6.5",
16 | "element-ui": "^2.13.2",
17 | "js-cookie": "^2.2.1",
18 | "js-hodgepodge": "^1.0.2",
19 | "node-sass": "^4.14.1",
20 | "nprogress": "^0.2.0",
21 | "sass-loader": "^9.0.1",
22 | "vue": "^2.6.11",
23 | "vue-router": "^3.3.4",
24 | "vuex": "^3.5.1"
25 | },
26 | "devDependencies": {
27 | "@babel/polyfill": "^7.11.5",
28 | "@vue/cli-plugin-babel": "~4.4.0",
29 | "@vue/cli-plugin-eslint": "~4.4.0",
30 | "@vue/cli-service": "~4.4.0",
31 | "babel-core": "^6.26.3",
32 | "babel-eslint": "^10.1.0",
33 | "babel-loader": "^7.1.5",
34 | "babel-plugin-component": "^1.1.1",
35 | "babel-preset-env": "^1.7.0",
36 | "eslint": "^6.7.2",
37 | "eslint-plugin-vue": "^6.2.2",
38 | "vue-template-compiler": "^2.6.11",
39 | "electron": "^12.0.2",
40 | "electron-builder": "^22.8.1"
41 | },
42 | "eslintConfig": {
43 | "root": true,
44 | "env": {
45 | "node": true
46 | },
47 | "extends": [
48 | "plugin:vue/essential",
49 | "eslint:recommended"
50 | ],
51 | "parserOptions": {
52 | "parser": "babel-eslint"
53 | },
54 | "rules": {}
55 | },
56 | "browserslist": [
57 | "> 1%",
58 | "last 2 versions",
59 | "not ie < 11"
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 模拟百度云盘
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | /public
6 |
7 | # local env files
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 | pnpm-debug.log*
16 |
17 | # Editor directories and files
18 | .idea
19 | .vscode
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | const createError = require('http-errors')
2 | const express = require('express')
3 | const path = require('path')
4 | const cookieParser = require('cookie-parser')
5 | const logger = require('morgan')
6 | const cors = require('cors')
7 | const indexRouter = require('./routes/index')
8 | const { scheduleCronstyle } = require('./tool/schedule')
9 |
10 | const app = express()
11 |
12 | // 开启全局定时任务
13 | scheduleCronstyle()
14 |
15 | app.set('views', path.join(__dirname, 'views'))
16 | app.set('view engine', 'jade')
17 |
18 | app.use(logger('dev'))
19 | app.use(express.json())
20 | app.use(express.urlencoded({ extended: false }))
21 | app.use(cookieParser())
22 | app.use(express.static(path.join(__dirname, 'public')))
23 | app.use(cors())
24 |
25 | app.use('/public', express.static(path.join(__dirname, 'public')))
26 | app.use('/', indexRouter)
27 |
28 | app.use(function(req, res, next) {
29 | next(createError(404))
30 | })
31 |
32 | app.use(function(err, req, res, next) {
33 | res.locals.message = err.message
34 | res.locals.error = req.app.get('env') === 'development' ? err : {}
35 |
36 | res.status(err.status || 500)
37 | res.render('error')
38 | })
39 |
40 | module.exports = app
41 |
--------------------------------------------------------------------------------
/server/bin/www:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | var app = require('../app');
8 | var debug = require('debug')('server:server');
9 | var http = require('http');
10 |
11 | /**
12 | * Get port from environment and store in Express.
13 | */
14 |
15 | var port = normalizePort(process.env.PORT || '3000');
16 | app.set('port', port);
17 |
18 | /**
19 | * Create HTTP server.
20 | */
21 |
22 | var server = http.createServer(app);
23 |
24 | /**
25 | * Listen on provided port, on all network interfaces.
26 | */
27 |
28 | server.listen(port);
29 | server.on('error', onError);
30 | server.on('listening', onListening);
31 |
32 | /**
33 | * Normalize a port into a number, string, or false.
34 | */
35 |
36 | function normalizePort(val) {
37 | var port = parseInt(val, 10);
38 |
39 | if (isNaN(port)) {
40 | // named pipe
41 | return val;
42 | }
43 |
44 | if (port >= 0) {
45 | // port number
46 | return port;
47 | }
48 |
49 | return false;
50 | }
51 |
52 | /**
53 | * Event listener for HTTP server "error" event.
54 | */
55 |
56 | function onError(error) {
57 | if (error.syscall !== 'listen') {
58 | throw error;
59 | }
60 |
61 | var bind = typeof port === 'string'
62 | ? 'Pipe ' + port
63 | : 'Port ' + port;
64 |
65 | // handle specific listen errors with friendly messages
66 | switch (error.code) {
67 | case 'EACCES':
68 | console.error(bind + ' requires elevated privileges');
69 | process.exit(1);
70 | break;
71 | case 'EADDRINUSE':
72 | console.error(bind + ' is already in use');
73 | process.exit(1);
74 | break;
75 | default:
76 | throw error;
77 | }
78 | }
79 |
80 | /**
81 | * Event listener for HTTP server "listening" event.
82 | */
83 |
84 | function onListening() {
85 | var addr = server.address();
86 | var bind = typeof addr === 'string'
87 | ? 'pipe ' + addr
88 | : 'port ' + addr.port;
89 | debug('Listening on ' + bind);
90 | }
91 |
--------------------------------------------------------------------------------
/server/db/createTable/createUserList.js:
--------------------------------------------------------------------------------
1 |
2 | const user_list = require('../user_list')
3 |
4 | user_list.sync({
5 | force: true
6 | })
7 |
--------------------------------------------------------------------------------
/server/db/createTable/cteateFileList.js:
--------------------------------------------------------------------------------
1 |
2 | const fileList = require('../fileList')
3 |
4 | fileList.sync({
5 | force: true
6 | })
7 |
--------------------------------------------------------------------------------
/server/db/fileList.js:
--------------------------------------------------------------------------------
1 | const Sequelize = require('sequelize')
2 | const db = require('./index')
3 |
4 | module.exports = db.defineModel('file_list', {
5 | f_id: { type: Sequelize.INTEGER, allowNull: false, primaryKey: true, unique: true, autoIncrement: true },
6 | f_name: { type: Sequelize.STRING() },
7 | f_size: { type: Sequelize.STRING() },
8 | f_dow_url: { type: Sequelize.STRING() },
9 | f_type: { type: Sequelize.STRING() },
10 | f_grouping: { type: Sequelize.STRING() },
11 | f_transfer_state: { type: Sequelize.INTEGER, defaultValue: 0 }, // 0 未下载, 1 已下载
12 | f_history_state: { type: Sequelize.INTEGER, defaultValue: 0 }, // 0 未删除, 1 已删除
13 | u_id: { type: Sequelize.INTEGER },
14 | u_name: { type: Sequelize.STRING }
15 | })
16 |
--------------------------------------------------------------------------------
/server/db/index.js:
--------------------------------------------------------------------------------
1 | const Sequelize = require('sequelize')
2 |
3 | const sqlConfig = { // mysql 基本配置
4 | host: 'localhost',
5 | user: 'root',
6 | password: 'root',
7 | database: 'network_disk'
8 | }
9 |
10 | console.log('init sequelize...')
11 |
12 | const sequelize = new Sequelize(sqlConfig.database, sqlConfig.user, sqlConfig.password, { // 连接mysql
13 | host: sqlConfig.host,
14 | dialect: 'mysql',
15 | pool: {
16 | max: 10,
17 | min: 0,
18 | idle: 10000
19 | },
20 | timezone: '+08:00'
21 | })
22 |
23 | exports.sequelize = sequelize // 抛出sequelize实例
24 |
25 | exports.defineModel = (name, attributes) => {
26 | const attrs = {}
27 | for (const key in attributes) { // 循环表字段
28 | const val = attributes[key]
29 | if (typeof val === 'object' && val['type']) {
30 | val.allowNull = val.allowNull || true
31 | attrs[key] = val
32 | } else {
33 | attrs[key] = {
34 | type: val
35 | }
36 | }
37 | }
38 | attrs.version = {
39 | type: Sequelize.BIGINT
40 | }
41 |
42 | return sequelize.define(name, attrs, { // 表默认配置
43 | tableName: name,
44 | timestamps: true,
45 | paranoid: true,
46 | charset: 'utf8mb4',
47 | collate: 'utf8mb4_general_ci',
48 | hooks: {
49 | beforeBulkCreate: (obj) => {
50 | obj.version = 0
51 | },
52 | beforeValidate: (obj) => {
53 | obj.isNewRecord ? obj.version = 0 : obj.version = obj.version + 1
54 | }
55 | }
56 | })
57 | }
58 |
--------------------------------------------------------------------------------
/server/db/user_list.js:
--------------------------------------------------------------------------------
1 |
2 | const Sequelize = require('sequelize')
3 | const db = require('./index') // 引入刚刚写的sequelize配置
4 |
5 | module.exports = db.defineModel('user_list', {
6 | u_id: { type: Sequelize.INTEGER, allowNull: false, primaryKey: true, unique: true, autoIncrement: true },
7 | u_name: { type: Sequelize.STRING },
8 | u_email: { type: Sequelize.STRING },
9 | u_capacity: { type: Sequelize.INTEGER(), defaultValue: 10 }, // 容量
10 | u_password: { type: Sequelize.STRING, defaultValue: 123456 },
11 | u_pic: { type: Sequelize.STRING(), defaultValue: 'https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png' } // 用户头像
12 | })
13 |
--------------------------------------------------------------------------------
/server/model/Result.js:
--------------------------------------------------------------------------------
1 | const {
2 | CODE_SUCCESS,
3 | CODE_ERROR,
4 | CODE_TOKEN_ERROR
5 | } = require('../tool/constant')
6 |
7 | class Result {
8 | constructor(data, msg = '操作成功!', options) {
9 | this.data = null
10 | if (arguments.length === 0) {
11 | this.msg = '操作成功!'
12 | } else if (arguments.length === 1) {
13 | this.msg = data
14 | } else {
15 | this.data = data
16 | this.msg = msg
17 | if (options) this.options = options
18 | }
19 | }
20 |
21 | content() {
22 | if (!this.code) {
23 | this.code = CODE_SUCCESS
24 | }
25 |
26 | const base = {
27 | code: this.code,
28 | msg: this.msg
29 | }
30 |
31 | if (this.data) {
32 | base.data = this.data
33 | }
34 |
35 | if (this.options) {
36 | base.options = this.options
37 | }
38 |
39 | return base
40 | }
41 |
42 | success(res) {
43 | this.code = CODE_SUCCESS
44 | this.send(res)
45 | }
46 |
47 | fail(res) {
48 | this.code = CODE_ERROR
49 | this.send(res)
50 | }
51 |
52 | send(res) {
53 | res.send(this.content())
54 | }
55 |
56 | tokenError(res) {
57 | this.code = CODE_TOKEN_ERROR
58 | this.send(res)
59 | }
60 | }
61 |
62 | module.exports = Result
63 |
--------------------------------------------------------------------------------
/server/model/file.js:
--------------------------------------------------------------------------------
1 | // const {} = require('../tool/constant')
2 |
3 | // class File {
4 | // constructor(file, userId) {
5 | // this.fileProcessing(file, userId)
6 | // }
7 |
8 | // fileProcessing(file) {
9 | // console.log(file)
10 |
11 | // const fileObj = {
12 | // f_name: file.originalname,
13 | // f_size: file.size,
14 | // f_path: file.path,
15 | // f_type: file.mimetype
16 | // }
17 | // }
18 | // }
19 |
20 | // module.exports = File
21 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "nodemon ./bin/www"
7 | },
8 | "dependencies": {
9 | "boom": "^7.3.0",
10 | "cookie-parser": "~1.4.4",
11 | "cors": "^2.8.5",
12 | "crypto": "^1.0.1",
13 | "debug": "~2.6.9",
14 | "express": "~4.16.1",
15 | "express-jwt": "^5.3.3",
16 | "express-validator": "^6.5.0",
17 | "http-errors": "~1.6.3",
18 | "jade": "^1.11.0",
19 | "jsonwebtoken": "^8.5.1",
20 | "morgan": "~1.9.1",
21 | "multer": "^1.4.2",
22 | "mysql": "^2.18.1",
23 | "mysql2": "^2.1.0",
24 | "node-schedule": "^2.0.0",
25 | "nodemailer": "^6.4.10",
26 | "nodemon": "^2.0.4",
27 | "sequelize": "^6.3.4"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/server/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 50px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
--------------------------------------------------------------------------------
/server/routes/file.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const router = express.Router()
3 | const { body } = require('express-validator')
4 | // const jwt = require('jsonwebtoken')
5 | const { errorChecking } = require('../tool/public')
6 | const Result = require('../model/Result')
7 | // const { md5, decoded } = require('../tool/index')
8 | // const { fs } = require('fs')
9 | const { mkdirFloader, getGroupingList } = require('../tool/file')
10 | const { UPLOAD_PATH } = require('../tool/constant')
11 | const { handleDelFile } = require('../servers/file')
12 |
13 | router.post('/create_folder',
14 | [
15 | body('currentPath').isLength({ min: 0 }).withMessage('当前路径不能为空'),
16 | body('folderName').isLength({ min: 0 }).withMessage('新增文件名不能为空')
17 | ], (req, res, next) => {
18 | errorChecking(next, req, () => {
19 | const { currentPath, folderName } = req.body
20 | const path = `${UPLOAD_PATH}/${currentPath}`
21 | const flag = mkdirFloader(folderName, path)
22 | console.log(flag)
23 | if (!flag) { return new Result('创建失败').fail(res) }
24 | new Result('创建成功').success(res)
25 | })
26 | })
27 |
28 | router.post('/grouping-list',
29 | [
30 | body('groupName').isLength({ min: 0 }).withMessage('当前路径不能为空')
31 | ], (req, res) => {
32 | getGroupingList(`${UPLOAD_PATH}/${req.body.groupName}`, list => {
33 | new Result(list, '获取成功').success(res)
34 | })
35 | })
36 |
37 | router.post('/del-file', [
38 | body('cur_url').isLength({ min: 0 }).withMessage('当前路径不能为空'),
39 | body('file_id').isLength({ min: 0 }).withMessage('文件ID不能为空')
40 | ], (req, res, next) => {
41 | errorChecking(next, req, () => {
42 | const { cur_url, file_id } = req.body
43 | handleDelFile(cur_url, file_id, data => {
44 | new Result('删除成功').success(res)
45 | })
46 | })
47 | })
48 |
49 | module.exports = router
50 |
--------------------------------------------------------------------------------
/server/routes/index.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const boom = require('boom')
3 | const userRouter = require('./users')
4 | const uploadRouter = require('./upload')
5 | const fileRouter = require('./file')
6 |
7 | const { jwtAuth } = require('./jwt')
8 | const Result = require('../model/Result')
9 | const router = express.Router()
10 | router.use(jwtAuth)
11 |
12 | router.use('/user', userRouter)
13 | router.use('/file', uploadRouter)
14 | router.use('/folder', fileRouter)
15 |
16 | router.use((req, res, next) => {
17 | next(boom.notFound('接口不存在'))
18 | })
19 |
20 | router.use((err, req, res, next) => {
21 | if (err.name && err.name === 'UnauthorizedError') { // 如果token验证失败
22 | const { status = 401, message } = err
23 | // 清楚用户cooick
24 | new Result(null, 'token验证失败', {
25 | error: status,
26 | errMsg: message
27 | }).tokenError(res.status(status))
28 | } else {
29 | const msg = (err && err.message) || '系统错误'
30 | const statusCode = (err.output && err.output.statusCode) || 500
31 | const errMsg = (err.output && err.output.playload && err.output.playload.error) || err.message
32 | new Result(null, msg, {
33 | error: statusCode,
34 | errMsg
35 | }).tokenError(res.status(statusCode))
36 | }
37 | })
38 | module.exports = router
39 |
--------------------------------------------------------------------------------
/server/routes/jwt.js:
--------------------------------------------------------------------------------
1 | const jwt = require('express-jwt')
2 | const { PRIVATE_KEY } = require('../tool/constant')
3 |
4 | const jwtAuth = jwt({
5 | secret: PRIVATE_KEY,
6 | credentialRequired: true
7 | }).unless({
8 | path: [
9 | '/',
10 | '/user/login',
11 | '/user/sendcode',
12 | '/user/register',
13 | '/user/user_check',
14 | '/file/dow_file'
15 | ]
16 | })
17 |
18 | module.exports = {
19 | jwtAuth
20 | }
21 |
--------------------------------------------------------------------------------
/server/routes/upload.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const router = express.Router()
3 | const Result = require('../model/Result')
4 | const multer = require('multer')
5 | const { UPLOAD_PATH } = require('../tool/constant')
6 | const fs = require('fs')
7 | const { uploadFile, uploadList, historyFile, historyList, handDelFile } = require('../servers/file')
8 | const { decoded } = require('../tool')
9 | const { body } = require('express-validator')
10 | const { errorChecking } = require('../tool/public')
11 |
12 | router.post('/upload',
13 | multer({ dest: `${UPLOAD_PATH}` }).single('file'), (req, res) => {
14 | const decode = decoded(req)
15 | if (decode && decode.username) {
16 | const { groupingName } = req.body
17 | const path = `${UPLOAD_PATH}/${groupingName}/${req.file.originalname}`
18 | const obj = {
19 | file: req.file,
20 | username: decode.username,
21 | fileDow: path,
22 | groupingName
23 | }
24 | fs.rename(`${req.file.path}`, path, function(err) { // 剪切刚刚上传的文件至分组
25 | console.log(err)
26 | })
27 | uploadFile(obj, data => {
28 | if (!data) return new Result('上传失败').fail(res)
29 | new Result('上传成功').success(res)
30 | })
31 | }
32 | })
33 |
34 | router.post('/upload-list',
35 | [
36 | body('uId').isLength({ min: 0 }).withMessage('用户ID不能为空')
37 | ], (req, res, next) => {
38 | errorChecking(next, req, () => {
39 | const { uId, groupingName } = req.body
40 | uploadList(uId, groupingName, data => {
41 | data.length > 0 ? new Result(data, '获取成功').success(res) : new Result([], '暂无数据').success(res)
42 | })
43 | })
44 | })
45 |
46 | router.post('/del-history', [
47 | body('file-id').isLength({ min: 0 }).withMessage('文件id不能为空')
48 | ], (req, res, next) => {
49 | errorChecking(next, req, () => {
50 | const { f_id } = req.body
51 | historyFile({ f_id }, data => {
52 | data.length > 0 ? new Result(data, '删除成功').success(res) : new Result('删除失败').fail(res)
53 | })
54 | })
55 | })
56 |
57 | router.post('/dow_file', [
58 | body('file_obj').isLength({ min: 0 }).withMessage('文件路径不能为空')
59 | ], (req, res, next) => {
60 | errorChecking(next, req, () => {
61 | try {
62 | handDelFile(req.body.file_obj.f_id, data => new Result(data, '下载成功!').success(res))
63 | } catch (e) {
64 | console.log(e)
65 | }
66 | // const realPath = `./${req.body.dow_url}`
67 | // res.writeHead(200, {
68 | // 'Content-Type': 'application/octet-stream',
69 | // 'Content-Disposition': 'attachment; filename=' + encodeURI(`${realPath.split('/')[realPath.split('/').length - 1]}`)
70 | // })
71 | // const readStream = fs.createReadStream(realPath)
72 | // readStream.on('data', (chunk) => {
73 | // res.write(chunk, 'binary')
74 | // })
75 | // readStream.on('end', () => {
76 | // res.end()
77 | // })
78 | })
79 | })
80 |
81 | router.get('/history', (req, res) => {
82 | const decode = decoded(req)
83 | historyList({ u_name: decode.username }, data => {
84 | data.length > 0 ? new Result(data, '获取成功').success(res) : new Result([], '暂无数据').success(res)
85 | })
86 | })
87 |
88 | module.exports = router
89 |
--------------------------------------------------------------------------------
/server/routes/users.js:
--------------------------------------------------------------------------------
1 | const express = require('express')
2 | const router = express.Router()
3 | const { body } = require('express-validator')
4 | const jwt = require('jsonwebtoken')
5 | const sendYzm = require('../tool/send')
6 | const { errorChecking } = require('../tool/public')
7 | const Result = require('../model/Result')
8 | const { login, usernameIsRegister, register, findUser } = require('../servers/user')
9 | const { md5, decoded } = require('../tool/index')
10 | const { PWD_SALT, JWT_EXPIRED, PRIVATE_KEY } = require('../tool/constant')
11 | const { mkdirFloader } = require('../tool/file')
12 |
13 | let YZM_CODE = ''
14 |
15 | router.get('/getUserInfo', (req, res) => {
16 | const decode = decoded(req)
17 | if (decode && decode.username) {
18 | findUser({ u_name: decode.username }, user => {
19 | if (!user) return new Result('查询失败').fail(res)
20 | new Result(user, '用户信息查询成功').success(res)
21 | })
22 | }
23 | })
24 |
25 | router.post('/login', [
26 | body('password').isLength({ min: 5 }).withMessage('密码长度太低'),
27 | body('username').isLength({ min: 4 }).withMessage('用户名长度太低')
28 | ], (req, res, next) => {
29 | errorChecking(next, req, () => {
30 | // eslint-disable-next-line prefer-const
31 | let { username, password } = req.body
32 | password = password === '123456' ? password : md5(`${password}${PWD_SALT}`)
33 | login({ u_name: username, u_password: password }, user => {
34 | if (!user || user.length === 0) { return new Result('登录失败').fail(res) }
35 | const token = jwt.sign(
36 | { username },
37 | PRIVATE_KEY,
38 | { expiresIn: JWT_EXPIRED }
39 | )
40 | new Result({ token }, '登录成功').success(res)
41 | })
42 | })
43 | })
44 |
45 | router.post('/sendcode', [
46 | body('email').isEmail().withMessage('请输入正确邮箱')
47 | ], (req, res, next) => {
48 | errorChecking(next, req, () => {
49 | YZM_CODE = ''
50 | const { email } = req.body
51 | for (let i = 0; i < 4; i++) {
52 | YZM_CODE += Math.floor(Math.random() * 10)
53 | }
54 | try {
55 | sendYzm.send(email, YZM_CODE)
56 | } catch (e) {
57 | console.log(e)
58 | }
59 | new Result(YZM_CODE, '验证码已发您邮件,请注意查收').success(res)
60 | })
61 | })
62 |
63 | router.post('/register', [
64 | body('username').isLength({ min: 6 }).withMessage('用户名长度太低'),
65 | body('email').isEmail().withMessage('邮箱不正确'),
66 | body('code').isLength({ min: 4, max: 4 }).withMessage('验证码不正确')
67 | ], (req, res, next) => {
68 | errorChecking(next, req, () => {
69 | register(req.body, YZM_CODE, data => {
70 | const flag = !mkdirFloader(req.body.username)
71 | if (!data || !flag) {
72 | return new Result('验证码不正确或邮箱已注册').fail(res)
73 | }
74 | new Result(data, '申请账号成功,24小时会有管理员回复,请注意邮箱提示').success(res)
75 | })
76 | })
77 | })
78 |
79 | router.post('/user_check', [
80 |
81 | body('username').isLength({ min: 6 }).withMessage('不能为空')
82 | ], (req, res, next) => {
83 | errorChecking(next, req, () => {
84 | const { username } = req.body
85 | usernameIsRegister({ u_name: username }, data => {
86 | data ? new Result('用户已被注册').success(res) : new Result('').success(res)
87 | })
88 | })
89 | })
90 |
91 | module.exports = router
92 |
--------------------------------------------------------------------------------
/server/servers/dbOperation.js:
--------------------------------------------------------------------------------
1 | // const Op = require('sequelize').Op
2 |
3 | /*
4 | * 根据条件查找新数据
5 | * @params option 配置对象
6 | * */
7 | function findOne(example, option, cb) {
8 | example.findOne({
9 | where: option
10 | }).then(res => {
11 | cb && cb(res)
12 | }).catch(err => {
13 | cb && cb(err)
14 | })
15 | }
16 |
17 | function findAll(example, option, cb) {
18 | example.findAll(
19 | option
20 | ).then(res => {
21 | cb && cb(res)
22 | })
23 | }
24 |
25 | /*
26 | * 创建一条新数据
27 | * @params option 配置对象
28 | * */
29 | function create(example, option, cb) {
30 | example.create(
31 | option
32 | ).then(list => {
33 | cb && cb(list)
34 | }).catch(() => {
35 | cb && cb(false)
36 | })
37 | }
38 |
39 | /*
40 | * 根据ID查一条数据
41 | * @params option 配置对象
42 | * */
43 | function findById(example, id, cb) {
44 | example.findById(id).then(list => {
45 | cb && cb(list)
46 | }).catch(err => {
47 | cb && cb(err)
48 | })
49 | }
50 |
51 | /*
52 | * 根据条件更新数据
53 | * @params option 配置对象
54 | * 示例:
55 | * option = { firstName: "King" },
56 | {
57 | where: { firstName: null }
58 | }
59 | * */
60 | function update(example, option, cb) {
61 | example.update(...option).then(list => {
62 | cb && cb(list)
63 | }).catch(err => {
64 | cb && cb(err)
65 | })
66 | }
67 |
68 | /*
69 | * 根据条件删除一条数据
70 | * @params option 配置对象
71 | * */
72 | function destroy(example, option, cb) {
73 | example.destroy(option).then(list => {
74 | cb && cb(list)
75 | }).catch(err => {
76 | cb && cb(err)
77 | })
78 | }
79 |
80 | module.exports = {
81 | findOne,
82 | create,
83 | findById,
84 | update,
85 | destroy,
86 | findAll
87 | }
88 |
--------------------------------------------------------------------------------
/server/servers/file.js:
--------------------------------------------------------------------------------
1 | const FileList = require('../db/fileList')
2 | const UserList = require('../db/user_list')
3 | const { findOne, create, findAll, update, destroy } = require('./dbOperation')
4 | const { delServerFile } = require('../tool/file')
5 |
6 | async function uploadFile(options, cb) {
7 | const { file, username, fileDow, groupingName } = options
8 | let u_id = null
9 | if (!file || file.length === 0) { return cb && cb(false) }
10 | await findOne(UserList, { u_name: username }, data => {
11 | u_id = data.dataValues.u_id
12 | const createObj = {
13 | f_name: file.originalname,
14 | f_size: file.size,
15 | f_dow_url: fileDow,
16 | f_grouping: groupingName || username,
17 | f_type: file.mimetype,
18 | u_id,
19 | u_name: username
20 | }
21 | create(FileList, createObj, data => {
22 | cb && cb(data)
23 | })
24 | })
25 | }
26 |
27 | function uploadList(uId, groupingName, cb) {
28 | if (groupingName.split('/').length === 0) {
29 | findAll(FileList, { where: { u_id: uId, f_history_state: 0 }}, data => {
30 | cb && cb(data)
31 | })
32 | } else {
33 | findAll(FileList, { where: { u_id: uId, f_history_state: 0, f_grouping: groupingName }}, data => {
34 | cb && cb(data)
35 | })
36 | }
37 | }
38 |
39 | function historyFile(options, cb) {
40 | const { f_id } = options
41 | const option = [
42 | { f_history_state: 1 },
43 | { where: { f_id }}
44 | ]
45 | update(FileList, option, data => {
46 | cb && cb(data)
47 | })
48 | }
49 |
50 | function historyList(options, cb) {
51 | findAll(FileList, { where: { ...options, f_history_state: 1 }}, data => {
52 | cb && cb(data)
53 | })
54 | }
55 |
56 | function handleDelFile(url, f_id, cb) {
57 | destroy(FileList, { where: { f_id }}, data => {
58 | // if(!data) { return cb && cb(false) }
59 | delServerFile(url, flag => {
60 | cb && cb('删除成功')
61 | })
62 | })
63 | }
64 |
65 | function handDelFile(f_id, cb) {
66 | update(FileList, [
67 | { f_transfer_state: 1 },
68 | { where: { f_id }}
69 | ], data => {
70 | cb && cb(data)
71 | })
72 | }
73 |
74 | module.exports = {
75 | uploadFile,
76 | uploadList,
77 | historyFile,
78 | historyList,
79 | handleDelFile,
80 | handDelFile
81 | }
82 |
--------------------------------------------------------------------------------
/server/servers/user.js:
--------------------------------------------------------------------------------
1 | const UserList = require('../db/user_list')
2 | const { create, findOne } = require('./dbOperation')
3 |
4 | function login(options, cb) {
5 | findOne(UserList, options, data => {
6 | cb && cb(data)
7 | })
8 | }
9 |
10 | function findUser(options, cb) {
11 | findOne(UserList, options, data => {
12 | cb && cb(data)
13 | })
14 | }
15 |
16 | function usernameIsRegister(options, cb) {
17 | findOne(UserList, options, data => {
18 | cb && cb(data)
19 | })
20 | }
21 |
22 | function register(body, YZM_CODE, cb) {
23 | const { username, email, code } = body
24 | if (YZM_CODE !== code) { return cb?.(false) }
25 | findOne(UserList, { u_email: email }, data => {
26 | if (data) { return cb?.(false) }
27 | create(UserList, {
28 | u_name: username,
29 | u_email: email
30 | }, res => {
31 | cb?.(res)
32 | })
33 | })
34 | }
35 |
36 | module.exports = {
37 | login,
38 | findUser,
39 | usernameIsRegister,
40 | register
41 | }
42 |
--------------------------------------------------------------------------------
/server/tool/constant.js:
--------------------------------------------------------------------------------
1 | const { env } = require('./env')
2 |
3 | const UPLOAD_PATH = env === 'dev' ? 'public/upload/users' : 'public/upload/users'
4 |
5 | module.exports = {
6 | CODE_ERROR: -1,
7 | CODE_SUCCESS: 200,
8 | PWD_SALT: 'admin_imooc_node',
9 | PRIVATE_KEY: 'admin_imooc_node_shan',
10 | JWT_EXPIRED: 60 * 60, // TOKEN 失效时间
11 | CODE_TOKEN_ERROR: -2,
12 | UPLOAD_PATH,
13 | TOURIST_PATH: `${UPLOAD_PATH}/tourist`
14 | // UPLOAD_URL
15 | }
16 |
--------------------------------------------------------------------------------
/server/tool/env.js:
--------------------------------------------------------------------------------
1 |
2 | const env = 'dev'
3 |
4 |
5 | module.exports = {
6 | env
7 | }
8 |
--------------------------------------------------------------------------------
/server/tool/file.js:
--------------------------------------------------------------------------------
1 | const { UPLOAD_PATH } = require('./constant')
2 | const fs = require('fs')
3 |
4 | function mkdirFloader(folderName, currentPath = UPLOAD_PATH) {
5 | const floaderList = fs.readdirSync(`${currentPath}`)
6 | if (floaderList.includes(folderName)) { return false }
7 | fs.mkdirSync(`${currentPath}/${folderName}`)
8 | return true
9 | }
10 |
11 | // function fileList(username) {
12 | // const floaderList = fs.readdirSync(`${UPLOAD_PATH} / ${username}`)
13 | // }
14 |
15 | function getGroupingList(path, cb) {
16 | let result = []
17 | list(path, data => {
18 | cb && cb(data)
19 | })
20 | function list(path, callBack) {
21 | const floaderList = fs.readdirSync(`${path}`)
22 | floaderList.forEach(file => {
23 | if (file.split('.').length === 1) {
24 | result = [...result, file]
25 | // list(`${path}/${file}`)
26 | }
27 | })
28 | callBack && callBack(result)
29 | }
30 | }
31 |
32 | function delServerFile(url, cb) {
33 | const path = `./${UPLOAD_PATH}/${url}`
34 | const flag = fs.unlinkSync(path)
35 | cb && cb(flag)
36 | }
37 |
38 | module.exports = {
39 | mkdirFloader,
40 | // fileList,
41 | getGroupingList,
42 | delServerFile
43 | }
44 |
--------------------------------------------------------------------------------
/server/tool/index.js:
--------------------------------------------------------------------------------
1 | const crypto = require('crypto')
2 | const jwt = require('jsonwebtoken')
3 | const { PRIVATE_KEY } = require('./constant')
4 |
5 | function md5(s) {
6 | return crypto.createHash('md5').update(String(s)).digest('hex')
7 | }
8 |
9 | function decoded(req) {
10 | let token = req.get('Authorization')
11 | if(token.indexOf('Bearer') === 0) {
12 | token = token.replace('Bearer ', '')
13 | }
14 | return jwt.verify(token, PRIVATE_KEY)
15 | }
16 |
17 | module.exports = {
18 | md5,
19 | decoded
20 | }
21 |
--------------------------------------------------------------------------------
/server/tool/public.js:
--------------------------------------------------------------------------------
1 | const boom = require('boom')
2 | const { validationResult } = require('express-validator')
3 |
4 | function errorChecking(next, req, cb) {
5 | const err = validationResult(req)
6 | if (!err.isEmpty()) {
7 | const [{ msg }] = err.errors
8 | next(boom.badRequest(msg))
9 | } else {
10 | cb && cb()
11 | }
12 | }
13 |
14 | module.exports = {
15 | errorChecking
16 | }
17 |
--------------------------------------------------------------------------------
/server/tool/schedule.js:
--------------------------------------------------------------------------------
1 | const schedule = require('node-schedule')
2 | const {
3 | TOURIST_PATH
4 | } = require('./constant')
5 |
6 | const fs = require('fs')
7 |
8 | function scheduleCronstyle() {
9 | schedule.scheduleJob('1 1 0 * * *', () => { // 每天的凌晨0点第一分钟的第一秒清空测试账号的数据 1 1 0 * * *
10 | delAllFile()
11 | })
12 | }
13 |
14 | function delAllFile(url = `${TOURIST_PATH}`) {
15 | const touristFileList = fs.readdirSync(url)
16 | touristFileList.forEach(c => {
17 | const path = `${url}/${c}`
18 | const start = fs.statSync(path)
19 | if (start.isDirectory()) {
20 | delAllFile(path)
21 | } else {
22 | fs.unlinkSync(path)
23 | }
24 | })
25 | url !== `${TOURIST_PATH}` && fs.rmdirSync(url)
26 | }
27 |
28 | module.exports = {
29 | scheduleCronstyle
30 | }
31 |
--------------------------------------------------------------------------------
/server/tool/send.js:
--------------------------------------------------------------------------------
1 | const nodemailer = require('nodemailer')
2 |
3 | const obj = {
4 | transporter: nodemailer.createTransport({
5 | host: 'smtp.qq.com', // 默认是这个
6 | port: 465,
7 | auth: {
8 | user: '272781702@qq.com',
9 | pass: 'rxnjazwslqdkbgei' // rxnjazwslqdkbgei
10 | }
11 | }),
12 |
13 | send: function(mail, content) {
14 | const mailOptions = {
15 | // 发送方的邮箱地址
16 | from: '桌面版百度云注册验证码<272781702@qq.com>',
17 | to: mail, // 对方邮箱
18 | // cc : '' //抄送 用于多人邮件
19 | // bcc : '' //密送
20 | subject: '激活验证码',
21 | text: `您的注册验证码为:${content}, 24小时内有效,请谨慎保管`,
22 | html: `
23 |
24 |
25 |
26 |
27 |
28 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
48 |
49 |
50 | 尊敬的用户:您好!
51 |
52 | 您正在进行ShanJDisc账号申请操作,请在验证码输入框中输入:${content},以完成操作。
53 |
54 |
55 |
56 |
57 |
58 | 注意:此操作可能会修改您的密码、登录邮箱或绑定手机。如非本人操作,请及时登录并修改密码以保证帐户安全
59 | (工作人员不会向你索取此验证码,请勿泄漏!)
60 |
61 |
62 |
63 |
64 |
65 |
66 | 此为系统邮件,请勿回复
67 | 请保管好您的邮箱,避免账号被他人盗用
68 |
69 | ShanJDisc
70 |
71 |
72 | |
73 |
74 |
75 |
76 |
77 | `
78 | }
79 | this.transporter.sendMail(mailOptions, (error, info) => {
80 | if (error) {
81 | return console.log(error)
82 | }
83 | console.log('Message sent: %s', info.messageId)
84 | })
85 | }
86 | }
87 |
88 | // 抛出对象以接收
89 |
90 | module.exports = obj
91 |
--------------------------------------------------------------------------------
/server/views/error.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= message
5 | h2= error.status
6 | pre #{error.stack}
7 |
--------------------------------------------------------------------------------
/server/views/index.jade:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | h1= title
5 | p Welcome to #{title}
6 |
--------------------------------------------------------------------------------
/server/views/layout.jade:
--------------------------------------------------------------------------------
1 | doctype html
2 | html
3 | head
4 | title= title
5 | link(rel='stylesheet', href='/stylesheets/style.css')
6 | body
7 | block content
8 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
24 |
--------------------------------------------------------------------------------
/src/api/file.js:
--------------------------------------------------------------------------------
1 | import request from '../utils/request'
2 | import store from '../store'
3 | import router from '../router'
4 |
5 | export function uploadFile(file, path) {
6 | const { name, size, type } = file
7 | const formData = new FormData()
8 | formData.append('file', file)
9 | formData.append('groupingName', path)
10 | let stime = new Date().getTime()
11 | let sloaded = 0
12 | return request({
13 | url: '/file/upload',
14 | headers: { 'Content-Type': 'multipart/form-data' },
15 | method: 'post',
16 | data: formData,
17 | onUploadProgress: progressEvent => {
18 | router.currentRoute.fullPath !== '/transfer/2' && router.push('/transfer/2')
19 | const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total)
20 | const endTime = new Date().getTime()
21 | const dTime = (endTime - stime) / 1000
22 | const dloaded = progressEvent.loaded - sloaded
23 | let speed = dloaded / dTime
24 | stime = new Date().getTime()
25 | sloaded = progressEvent.loaded
26 | let unit = 'b/s'
27 | if (speed / 1024 > 1) {
28 | unit = 'kb/s'
29 | speed = speed / 1024
30 | }
31 | if (speed / 1024 > 1) {
32 | unit = 'mb/s'
33 | speed = speed / 1024
34 | }
35 | store.dispatch('onUploadProgress',
36 | {
37 | progressBar: percentCompleted,
38 | sloaded: dloaded,
39 | dloadedremainingTime: dTime,
40 | uploadSpeed: speed.toFixed(2) + unit,
41 | fileName: name,
42 | fileSize: size,
43 | fileType: type
44 | }
45 | )
46 | }
47 | })
48 | }
49 |
50 | export function uploadList(uId, groupingName) {
51 | return request({
52 | url: '/file/upload-list',
53 | method: 'post',
54 | data: {
55 | uId,
56 | groupingName
57 | }
58 | })
59 | }
60 |
61 | export function uploadHistory(f_id) {
62 | return request({
63 | url: '/file/del-history',
64 | method: 'post',
65 | data: {
66 | f_id
67 | }
68 | })
69 | }
70 |
71 | export function getHistory() {
72 | return request({
73 | url: '/file/history',
74 | method: 'get'
75 | })
76 | }
77 |
78 | export function createFloader(currentPath, folderName) {
79 | return request({
80 | url: '/folder/create_folder',
81 | method: 'post',
82 | data: {
83 | currentPath,
84 | folderName
85 | }
86 | })
87 | }
88 |
89 | export function groupingList(groupName) {
90 | return request({
91 | url: '/folder/grouping-list',
92 | method: 'post',
93 | data: {
94 | groupName
95 | }
96 | })
97 | }
98 |
99 | export function delFile(cur_url, file_id) {
100 | return request({
101 | url: '/folder/del-file',
102 | method: 'post',
103 | data: {
104 | cur_url,
105 | file_id
106 | }
107 | })
108 | }
109 |
110 | export function dowFile(file) {
111 | console.log('file', file)
112 | // return request({
113 | // url: '/file/dow_file',
114 | // method: 'post',
115 | // data: file
116 | // })
117 | }
118 |
--------------------------------------------------------------------------------
/src/api/user.js:
--------------------------------------------------------------------------------
1 | import request from '../utils/request'
2 |
3 | export function login(options) {
4 | return request({
5 | url: '/user/login',
6 | method: 'post',
7 | data: options
8 | })
9 | }
10 |
11 | export function getUserInfo() {
12 | return request({
13 | url: '/user/getUserInfo',
14 | method: 'get'
15 | })
16 | }
17 |
18 | export function applicationAccountNumber(formData) {
19 | const { username, email, yzm } = formData
20 | return request({
21 | url: '/user/register',
22 | method: 'post',
23 | data: {
24 | username,
25 | email,
26 | code: yzm
27 | }
28 | })
29 | }
30 |
31 | export function sendEmailCode(email) {
32 | return request({
33 | url: '/user/sendcode',
34 | method: 'post',
35 | data: {
36 | email
37 | }
38 | })
39 | }
40 |
41 | export function userCheck(username) {
42 | return request({
43 | url: '/user/user_check',
44 | method: 'post',
45 | data: {
46 | username
47 | },
48 | onUploadProgress: progressEvent => {
49 | console.log((progressEvent.loaded / progressEvent.total * 100 | 0) + '%')
50 | }
51 | })
52 | }
53 |
--------------------------------------------------------------------------------
/src/assets/font/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "iconfont";
2 | src: url('iconfont.eot?t=1594733024019'); /* IE9 */
3 | src: url('iconfont.eot?t=1594733024019#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAZIAAsAAAAADBwAAAX6AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCENgqJQIdKATYCJAMsCxgABCAFhG0HgRobRAoRVaSxkv0ojBvuYilK9EceITQC7WL8FEss7vdD8DzpfX9uJtrJJgvwo7Kc6ksdpM6oIHXw++k96wXVTLmk04X0x0vPKo/gH5gDtKjTdoyvrn3Bs+/4An4VR4aQXFspHH+/0o2mXbAce7Yu1X1dgBVAB/TfRYRVCBXoidot4tl0FwpPzMnLIYAmGx+IRmk5JeBiwvQCbUa1t9aDm3Jg1vAE12yXHGoqZC5YuMY08gaw3P6+fKKCCAEDSwG7UruW1Caox2HuNBX+D+lFsRDi+YDJUaCA8gAmyIHSwC5QvlAeCr3Cm8wCSEYOhY31N+VyxVwp15BL5RhugNvOnf4fARiOzSQk80YgCoVzdf7hWdgIGgPEBmqI1qYFqaKGt1giRMFbBwQFb90QHHjrgeDC22QEE96mIljwlkGw4e0AgsDb7Yr9GI9BNwwAPH1IMkAhIH0AOQcztbI+B4NTlc72HUzMgM8X0rCn3KcFUrniiSkp31ojmlWJ5QHfOEpeVCYZFq9eD3a4wVW2bhNhVUkFEvBMTTiIQXbaRpcySlSi7oJLcQlSYtDSK56+EAgXYX+GmhD14oaOZHxnwS1NmFGAfKZPlja1MMMMrVmPgrUbrQT6Tbh7ee8YgysRglxiWxnxsKSZlg/tgplhOzFIWYI6m8UdqCyXcFQP7DNo+kaiG6FSz1gE7J7hDZrDIdOTwXB70d3sZfea7hmOm7EbjHil2lSVQHbSxTbVWn4Xo5GeEFVQElIpBn+qwp2+7UAay8q7TbB82ZFecaex4tw9Z14mNl269uih2Y65H8ajaA4PrT7iiluqdBvRIo+oTcfx4itZhtuZaOW1Tup1ezZo1u/deLh4w/VK0r03swXLbg1sRu7+6rwZrmvOprHr1u9HGnRXPGOdWq/TrTVbrLXbrdrsuK8WMouv41zrRrjWoqEmASOPLhalBeqOt5Ij1el36t7JGGeLq1OSRBDNrPYcFo+ZGaHqbII9qrHU8GHLbe+yFyYVdo+yb3p2mr9t11rw1tywjs/2MsC0QGlEIPk8p2DGfTWZSPVeUGZr+D9y07yXdLndJZ6OdlAN65MZEf+dEtoIx42L+WX7HRFJ4dTxNvIfnInsH9PbF/EVhxtW5tWsr1PfYoTv2FTQoD2lPUf8LsnMDI3f+vplnWmupd1l0xDQXkmStacdd+kXvp/8zhMXRSc5sk3gH/to/Vy9W1gxksR1h8BQ7KNAESQ4JmhO3LKq4JHv5LP+/vKWbXzEi/hx9Iec03lsHqT8Y9nkcenpAnLxdKJpcr9sa0BCU8GoQEUDtuYmwqkmE/WToXIYbv+glY2QaT88TTZbanzS8xXXpMvv0d4AKsTbtudQz7M8zAXZCT6isNh3TZfZjys0je8rNANxQrgpIrrdcu43p86Zl8V3usTc+qDd4iPsP82zijhMkPB631yL3IWREfvrx7VGGq1ByfxbfiLMrQMgclQ1p2IBUC55ZJlbrBZQSVbEqjVUSF2Y36WGUrngMvPLTFupvI1R3vFNVsn6H62NifkmxL+kRY+Cbz6LZP0UeC7c9z4o8B/pR2uByH9TN1UzBcbIJDlvwuq0oqfIowKCLxiARgP/jEg89/FNSa0N/B1NSTEYOGSBwqWQbNLLg4VHJbBxqQuacqQf7ZHAACjEFAGUZRIBIZZtYBBwGhSxXCGb9HtgkcxbsIkVCiQH/MrlKQ+5E3dwHwiFaqjW4BQPWrjlwLX9JDN2GJJqy/+lEF0aijTPlp9poICxR1yYUkSDDtzDE7kadR2DD9yQktSK+FmW6bInShX3kwPuCRCIQNQAFWsAh4IZ0Hp64SD3858QhpEOJNQMuZL8hQhE3NqBgpS8BfnZMLQa8lg6RxYYSoTmNICetDI9wBP1ER0vMIAv36iBUAgptkfOMyOjU+m2hnT/pv7xXgVo2P14YogSUyyxxRFXokSLJ9Fs1v99PYgWB6PsqD/nqObl0DHWievN1t/b58PG4//Jgp0iHWg+0qDW+2uMI1fIydmShsah1JmOrZU7mjvBgvpk03uZTAAA') format('woff2'),
5 | url('iconfont.woff?t=1594733024019') format('woff'),
6 | url('iconfont.ttf?t=1594733024019') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
7 | url('iconfont.svg?t=1594733024019#iconfont') format('svg'); /* iOS 4.1- */
8 | }
9 |
10 | .iconfont {
11 | font-family: "iconfont" !important;
12 | font-size: 16px;
13 | font-style: normal;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | .icon-AVI:before {
19 | content: "\e672";
20 | }
21 |
22 | .icon-shangchuan:before {
23 | content: "\e6bf";
24 | margin-right: 5px;
25 | width: 30px;
26 | text-align: center;
27 | font-size: 24px;
28 | vertical-align: middle;
29 | }
30 |
31 | .icon-download-img:before {
32 | content: "\e620";
33 | margin-right: 5px;
34 | width: 24px;
35 | text-align: center;
36 | font-size: 18px;
37 | vertical-align: middle;
38 | }
39 |
40 | .icon-WORD:before {
41 | content: "\e643";
42 | }
43 |
44 | .icon-EX:before {
45 | content: "\e645";
46 | }
47 |
48 | .icon-voicefrequency:before {
49 | content: "\e655";
50 | }
51 |
52 | .icon-yasuobao-:before {
53 | content: "\e626";
54 | }
55 |
56 | .icon-wenjianjiaguanbi:before {
57 | content: "\e628";
58 | }
59 |
60 | .icon-qitawenjian-:before {
61 | content: "\e60b";
62 | }
63 |
64 | .icon-ppt:before {
65 | content: "\e6b0";
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/src/assets/font/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/font/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/font/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
57 |
--------------------------------------------------------------------------------
/src/assets/font/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/font/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/font/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/font/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/font/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/font/iconfont.woff2
--------------------------------------------------------------------------------
/src/assets/images/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/404.png
--------------------------------------------------------------------------------
/src/assets/images/AVI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/AVI.png
--------------------------------------------------------------------------------
/src/assets/images/WORD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/WORD.png
--------------------------------------------------------------------------------
/src/assets/images/excel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/excel.png
--------------------------------------------------------------------------------
/src/assets/images/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/img.png
--------------------------------------------------------------------------------
/src/assets/images/mp3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/mp3.png
--------------------------------------------------------------------------------
/src/assets/images/no-data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/no-data.png
--------------------------------------------------------------------------------
/src/assets/images/ppt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/ppt.png
--------------------------------------------------------------------------------
/src/assets/images/qita.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/qita.png
--------------------------------------------------------------------------------
/src/assets/images/zip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/assets/images/zip.png
--------------------------------------------------------------------------------
/src/assets/reset.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Eric Meyer's Reset CSS v2.0 (http://meyerweb.com/eric/tools/css/reset/)
3 | * http://cssreset.com
4 | */
5 | html,
6 | body,
7 | div,
8 | span,
9 | applet,
10 | object,
11 | iframe,
12 | p,
13 | blockquote,
14 | pre,
15 | a,
16 | abbr,
17 | acronym,
18 | address,
19 | big,
20 | cite,
21 | code,
22 | del,
23 | dfn,
24 | em,
25 | img,
26 | ins,
27 | kbd,
28 | q,
29 | s,
30 | samp,
31 | small,
32 | strike,
33 | strong,
34 | sub,
35 | sup,
36 | tt,
37 | var,
38 | b,
39 | u,
40 | i,
41 | center,
42 | dl,
43 | dt,
44 | dd,
45 | ol,
46 | ul,
47 | li,
48 | fieldset,
49 | form,
50 | label,
51 | legend,
52 | table,
53 | caption,
54 | tbody,
55 | tfoot,
56 | thead,
57 | tr,
58 | th,
59 | td,
60 | article,
61 | aside,
62 | canvas,
63 | details,
64 | embed,
65 | figure,
66 | figcaption,
67 | footer,
68 | header,
69 | menu,
70 | nav,
71 | output,
72 | ruby,
73 | section,
74 | summary,
75 | time,
76 | mark,
77 | audio,
78 | video,
79 | input {
80 | margin: 0;
81 | padding: 0;
82 | border: 0;
83 | font-size: 100%;
84 | font-weight: normal;
85 | vertical-align: baseline;
86 | box-sizing: border-box;
87 | }
88 |
89 | /* HTML5 display-role reset for older browsers */
90 | article,
91 | aside,
92 | details,
93 | figcaption,
94 | figure,
95 | footer,
96 | header,
97 | menu,
98 | nav,
99 | section {
100 | display: block;
101 | }
102 |
103 | body {
104 | line-height: 1;
105 | }
106 |
107 | body,
108 | html {
109 | height: 100%;
110 | }
111 |
112 | blockquote,
113 | q {
114 | quotes: none;
115 | }
116 |
117 | blockquote:before,
118 | blockquote:after,
119 | q:before,
120 | q:after {
121 | content: none;
122 | }
123 |
124 | table {
125 | border-collapse: collapse;
126 | border-spacing: 0;
127 | }
128 |
129 | /* custom */
130 | a {
131 | color: #999;
132 | text-decoration: none;
133 | -webkit-backface-visibility: hidden;
134 | }
135 |
136 | li {
137 | list-style: none;
138 | }
139 |
140 | ::-webkit-scrollbar {
141 | width: 5px;
142 | height: 5px;
143 | }
144 |
145 | ::-webkit-scrollbar-track-piece {
146 | background-color: rgba(0, 0, 0, 0.2);
147 | -webkit-border-radius: 6px;
148 | }
149 |
150 | ::-webkit-scrollbar-thumb:vertical {
151 | height: 5px;
152 | background-color: rgba(125, 125, 125, 0.7);
153 | -webkit-border-radius: 6px;
154 | }
155 |
156 | ::-webkit-scrollbar-thumb:horizontal {
157 | width: 5px;
158 | background-color: rgba(125, 125, 125, 0.7);
159 | -webkit-border-radius: 6px;
160 | }
161 |
162 | /*html, body {*/
163 | /*width: 100%;*/
164 | /*height: 100%;*/
165 | /*}*/
166 |
167 | body {
168 | -webkit-text-size-adjust: none;
169 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
170 | }
171 |
172 | /*显示省略号*/
173 | .ellipsis {
174 | overflow: hidden;
175 | text-overflow: ellipsis;
176 | white-space: nowrap;
177 | }
178 |
179 | .ellipsis-one {
180 | display: -webkit-box;
181 | -webkit-box-orient: vertical;
182 | -webkit-line-clamp: 3;
183 | overflow: hidden;
184 | }
185 |
186 | /*常用的弹性布局*/
187 | .dispaly-flex {
188 | display: flex;
189 | justify-content: space-between;
190 | align-items: center;
191 | }
192 |
193 | .dispaly-center {
194 | display: flex;
195 | align-items: center;
196 | }
197 |
198 | .dispaly-space {
199 | display: flex;
200 | justify-content: space-between;
201 | }
202 |
203 | .dispaly-content-center {
204 | display: flex;
205 | justify-content: center;
206 | }
207 |
208 | .d-c-c {
209 | display: flex;
210 | justify-content: center;
211 | align-items: center;
212 | }
213 |
214 | .dispaly {
215 | display: flex;
216 | }
217 |
218 | .warp {
219 | flex-wrap: wrap;
220 | }
221 |
222 | .text-center {
223 | text-align: center;
224 | }
225 |
226 | .f1 {
227 | flex: 1;
228 | }
229 |
230 | .p1 {
231 | padding: 10px;
232 | }
233 |
234 | .p2 {
235 | padding: 20px;
236 | }
237 |
238 | .p3 {
239 | padding: 30px;
240 | }
241 |
242 | .p4 {
243 | padding: 40px;
244 | }
245 |
246 | .p5 {
247 | padding: 50px;
248 | }
249 |
250 | .pl-1 {
251 | padding-left: 10px;
252 | }
253 |
254 | .pl-2 {
255 | padding-left: 20px;
256 | }
257 |
258 | .pl-3 {
259 | padding-left: 30px;
260 | }
261 | .pr-1 {
262 | padding-right: 10px;
263 | }
264 |
265 | .pr-2 {
266 | padding-right: 20px;
267 | }
268 |
269 | .pr-3 {
270 | padding-right: 30px;
271 | }
272 |
273 | .pt-1 {
274 | padding-top: 10px;
275 | }
276 |
277 | .pt-2 {
278 | padding-top: 20px;
279 | }
280 |
281 | .pt-3 {
282 | padding-top: 30px;
283 | }
284 | .pb-1 {
285 | padding-bottom: 10px;
286 | }
287 |
288 | .pb-2 {
289 | padding-bottom: 20px;
290 | }
291 |
292 | .pb-3 {
293 | padding-bottom: 30px;
294 | }
295 |
296 | .pb-5 {
297 | padding-bottom: 50px;
298 | }
299 |
300 | .ml-1 {
301 | margin-left: 10px;
302 | }
303 |
304 | .ml-2 {
305 | margin-left: 20px;
306 | }
307 |
308 | .ml-3 {
309 | margin-left: 30px;
310 | }
311 |
312 | .mr-1 {
313 | margin-right: 10px;
314 | }
315 | .mr-2 {
316 | margin-right: 20px;
317 | }
318 |
319 | .mr-3 {
320 | margin-right: 30px;
321 | }
322 |
323 | .mt-1 {
324 | margin-top: 10px;
325 | }
326 | .mt-2 {
327 | margin-top: 20px;
328 | }
329 |
330 | .mt-3 {
331 | margin-top: 30px;
332 | }
333 |
334 | .mb-1 {
335 | margin-bottom: 10px;
336 | }
337 |
338 | .mb-2 {
339 | margin-bottom: 20px;
340 | }
341 |
342 | .mb-3 {
343 | margin-bottom: 30px;
344 | }
345 |
346 |
347 |
--------------------------------------------------------------------------------
/src/assets/scss/index.scss:
--------------------------------------------------------------------------------
1 | @mixin border-bottom ($color) {
2 | border-bottom: 1px solid $color;
3 | }
4 |
5 | @mixin dispaly-flex() {
6 | display: flex;
7 | justify-content: space-between;
8 | align-items: center;
9 | }
10 |
11 | @mixin dispaly-center() {
12 | display: flex;
13 | align-items: center;
14 | }
15 |
16 | @mixin dispaly-space() {
17 | display: flex;
18 | justify-content: space-between;
19 | }
20 |
21 | @mixin dispaly-content-center() {
22 | display: flex;
23 | justify-content: center;
24 | }
25 |
26 | @mixin d-c-c() {
27 | display: flex;
28 | justify-content: center;
29 | align-items: center;
30 | }
31 |
32 | @mixin ellipsis() {
33 | overflow: hidden;
34 | text-overflow: ellipsis;
35 | white-space: nowrap;
36 | }
37 | /*
38 | $size : 显示几行
39 | */
40 | @mixin ellipsis-one($size) {
41 | display: -webkit-box;
42 | -webkit-box-orient: vertical;
43 | -webkit-line-clamp: $size;
44 | overflow: hidden;
45 | }
46 |
47 | @mixin text-center($size, $color) {
48 | font-size: $size;
49 | color: $color;
50 | text-align: center;
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/DownloadList/DownloadList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
![]()
8 |
9 |
{{ file.f_name }}
10 |
11 |
12 |
文件大小:{{ file.f_size | byte }}
13 |
下载速度:{{ file.speedBytes | byte }}/s
14 |
等待中
15 |
已下载:{{ file.offset | byte }}
16 |
17 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
46 |
![]()
47 |
48 |
{{ file.fileName || file.f_name }}
49 |
50 | {{ file.f_size | byte }}
51 | 地址:{{ file.path }}
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
161 |
162 |
210 |
211 |
259 |
--------------------------------------------------------------------------------
/src/components/DownloadList/cop.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 | {{ file.fileName || file.f_name }}
7 | {{ file.sloaded }} / {{ file.fileSize }}
8 | {{ fileSize(file) }}
9 |
10 |
11 | {{ file.uploadSpeed }}
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
100 |
101 |
149 |
--------------------------------------------------------------------------------
/src/components/Mark/Mark.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
24 |
25 |
47 |
--------------------------------------------------------------------------------
/src/components/NoData/NoData.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
12 |
13 |
22 |
--------------------------------------------------------------------------------
/src/components/Upload/Upload.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 | 下载
14 |
15 |
16 |
17 |
18 |
100 |
101 |
119 |
--------------------------------------------------------------------------------
/src/components/funcTool/funcTool.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
24 |
25 |
34 |
--------------------------------------------------------------------------------
/src/components/progress/progress.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/src/electron/icon/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LIAOJIANS/ShanJ-disc/ae5efe55447100b67fabd5b2e7e8f50925e77684/src/electron/icon/logo.png
--------------------------------------------------------------------------------
/src/electron/index.js:
--------------------------------------------------------------------------------
1 | const { app, BrowserWindow } = require('electron')
2 |
3 | // 获取单例锁
4 | const gotTheLock = app.requestSingleInstanceLock()
5 |
6 | if (!gotTheLock) {
7 | app.quit()
8 | } else {
9 | const { mainWindowIpcStart } = require('./lib/ipcMain')
10 | const path = require('path')
11 | global.appDirname = __dirname
12 |
13 | app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')
14 |
15 | const winURL = path.resolve(__dirname, '../renderer/index.html')
16 |
17 | let mainWindow
18 | // eslint-disable-next-line no-inner-declarations
19 | function createWindow() {
20 | const win = new BrowserWindow({
21 | width: 1580,
22 | height: 888,
23 | // resizable: false,
24 | // useContentSize: true,
25 | /* transparent: true, */
26 | icon: path.resolve(__dirname, './icon/logo.png'),
27 | frame: false,
28 | show: false,
29 | webPreferences: {
30 | webSecurity: false,
31 | nodeIntegration: true,
32 | contextIsolation: false,
33 | webviewTag: true
34 | }
35 | })
36 | /* win.maximize(); */
37 | // console.log(app.isPackaged)
38 | if (app.isPackaged) {
39 | win.loadURL(`file://${winURL}`)
40 | } else {
41 | win.loadURL('http://localhost:8080')
42 | win.webContents.openDevTools()
43 | }
44 |
45 | win.on('closed', () => { mainWindow = null })
46 | win.on('ready-to-show', () => { win.show() })
47 | return win
48 | }
49 |
50 | app.on('ready', function() {
51 | // eslint-disable-next-line new-cap
52 | mainWindow = new createWindow()
53 | mainWindowIpcStart(mainWindow)
54 | })
55 |
56 | app.on('second-instance', (event, commandLine, workingDirectory) => {
57 | // 当运行第二个实例时,将会聚焦到myWindow这个窗口
58 | if (mainWindow) {
59 | if (mainWindow.isMinimized()) mainWindow.restore()
60 | mainWindow.focus()
61 | }
62 | })
63 |
64 | app.on('quit', () => {
65 | app.releaseSingleInstanceLock()// 释放所有的单例锁
66 | })
67 | }
68 |
--------------------------------------------------------------------------------
/src/electron/lib/ipcMain.js:
--------------------------------------------------------------------------------
1 | const { app, ipcMain, session, Notification, shell, dialog } = require('electron')
2 | const path = require('path')
3 | const fs = require('fs')
4 | const axios = require('axios')
5 |
6 | // 缓存下载项
7 | const cacheDownItem = {}
8 |
9 | const mainWindowIpcStart = function(win) {
10 | // 打开调试
11 | ipcMain.on('toggle_dev_tools', function(event, arg) {
12 | win.webContents.toggleDevTools()
13 | })
14 |
15 | // 重启
16 | ipcMain.on('restart', function() {
17 | app.relaunch()
18 | app.exit(0)
19 | })
20 |
21 | // 最小化
22 | ipcMain.on('min', function() {
23 | win.minimize()
24 | })
25 |
26 | // 最大化
27 | ipcMain.on('max', function() {
28 | if (win.isMaximized()) {
29 | win.unmaximize()
30 | } else {
31 | win.maximize()
32 | }
33 | })
34 |
35 | // 关闭程序
36 | ipcMain.on('close', function() {
37 | cacheDownItemClose()
38 | win.close()
39 | })
40 |
41 | // 设置下载路径
42 | ipcMain.on('set_path', (e, data = {}) => {
43 | const { path } = data
44 | if (path) {
45 | if (path !== 'not') app.setPath('downloads', path)
46 | e.reply('set_path', app.getPath('downloads'))
47 | } else {
48 | dialog.showOpenDialog({
49 | title: '选择下载目录',
50 | defaultPath: app.getPath('downloads'),
51 | properties: ['openDirectory']
52 | }).then((files) => {
53 | if (!files.canceled) { // 如果有选中
54 | app.setPath('downloads', files.filePaths[0])
55 | }
56 | e.reply('set_path', files)
57 | })
58 | }
59 | })
60 |
61 | // 在应用中打开文件
62 | ipcMain.on('check_path', (e, data = {}) => {
63 | const { path } = data
64 | fs.access(path, fs.constants.F_OK, (err) => { // 利用fs 读取文件路径
65 | if (!err) {
66 | shell.showItemInFolder(path) // 打开文件
67 | }
68 | e.reply('check_path' + path, err)
69 | })
70 | })
71 |
72 | // 下载
73 | ipcMain.on('down-file', function(e, data) {
74 | const { f_dow_url } = data
75 | if (!cacheDownItem[f_dow_url]) {
76 | cacheDownItem[f_dow_url] = { ...data }
77 | downfile(f_dow_url)
78 | } else {
79 | e.sender('down-file', '文件正在下载')
80 | }
81 | })
82 |
83 | // 暂停
84 | ipcMain.on('down-file-pause', function(e, data) {
85 | const { url } = data
86 | const t = cacheDownItem[url]
87 | if (t) {
88 | t._downFileItem.pause()
89 | }
90 | e.reply('down-file-pause-' + url, '已暂停')
91 | })
92 |
93 | // 继续
94 | ipcMain.on('down-file-resume', function(e, data) {
95 | const { url } = data
96 | const t = cacheDownItem[url]
97 | if (t) {
98 | t._downFileItem.resume()
99 | }
100 | e.reply('down-file-resume-' + url, '已恢复下载')
101 | })
102 |
103 | // 取消下载
104 | ipcMain.on('down-file-cancel', function(e, data) {
105 | const { url } = data
106 | const t = cacheDownItem[url]
107 | if (t) {
108 | t._downFileItem.cancel()
109 | } else {
110 | // 删除未下在完成文件
111 | }
112 | e.reply('down-file-cancel-' + url, '已取消下载')
113 | })
114 |
115 | // 断点恢复下载
116 | ipcMain.on('resume-download', function(e, data) {
117 | const { url } = data
118 | const t = cacheDownItem[url]
119 | if (t) {
120 | t._downFileItem.resume()
121 | } else {
122 | cacheDownItem[url] = { ...data }
123 | resumeDownload(data)
124 | }
125 | e.reply('down-file-resume-' + url, '已恢复下载')
126 | })
127 |
128 | // 下载文件
129 | const downfile = (url) => {
130 | session.defaultSession.downloadURL(url)
131 | }
132 |
133 | // 恢复下载
134 | const resumeDownload = (obj = {}) => {
135 | const { path = '', urlChain = [], offset = 0, length = 0, lastModified, eTag, startTime } = obj
136 | if (!path || urlChain.length === 0 || length === 0) {
137 | return
138 | }
139 | session.defaultSession.createInterruptedDownload({
140 | path, urlChain, offset, length, lastModified, eTag, startTime
141 | })
142 | }
143 |
144 | // 监听下载
145 | session.defaultSession.on('will-download', (e, item) => {
146 | try {
147 | const url = item.getURL()
148 | let cacheItem = cacheDownItem[url] || {
149 | notSend: true
150 | }
151 | // 获取文件的总大小
152 | const totalBytes = item.getTotalBytes()
153 | // 设置下载路径
154 | const filePath = path.join(app.getPath('downloads'), item.getFilename())
155 | item.setSavePath(filePath)
156 |
157 | // eslint-disable-next-line no-irregular-whitespace
158 | // 缓存downitem
159 | cacheItem._downFileItem = item
160 | cacheItem.path = item.getSavePath()
161 | cacheItem.eTag = item.getETag()
162 | cacheItem.urlChain = item.getURLChain()
163 | cacheItem.length = totalBytes
164 | cacheItem.lastModified = item.getLastModifiedTime()
165 | cacheItem.startTime = item.getStartTime()
166 |
167 | let lastBytes = 0
168 |
169 | // 监听下载过程,计算并设置进度条进度
170 | item.on('updated', (event, state) => {
171 | if (state === 'interrupted') {
172 | cacheItem.state = 'interrupted'
173 | } else if (state === 'progressing') {
174 | if (item.isPaused()) {
175 | cacheItem.state = 'paused'
176 | } else {
177 | const offset = item.getReceivedBytes()
178 | cacheItem.state = 'downing'
179 | cacheItem.speedBytes = offset - lastBytes
180 | cacheItem.progress = parseInt((offset / totalBytes) * 100)
181 | cacheItem.offset = offset
182 | lastBytes = offset
183 | }
184 | }
185 | !cacheItem.notSend && win.webContents.send('update-down-state', JSON.parse(JSON.stringify(cacheItem)))
186 | })
187 |
188 | // 下载完成
189 | item.once('done', (event, state) => {
190 | cacheItem.done = 'end'
191 | switch (state) {
192 | case 'interrupted':
193 | cacheItem.state = 'interrupted-err'
194 | break
195 | case 'cancelle':
196 | cacheItem.state = 'cancelle'
197 | break
198 | default:
199 | cacheItem.state = 'completed'
200 | notification(cacheItem.path)
201 | break
202 | }
203 |
204 | !cacheItem.notSend && win.webContents.send('update-down-state', JSON.parse(JSON.stringify(cacheItem)))
205 |
206 | // 请求后端改变文件状态
207 | axios.post('http://192.168.1.64:3000/file/dow_file',
208 | { file_obj: cacheDownItem[url] },
209 | {
210 | headers: {
211 | 'Content-Type': 'application/json;charset=UTF-8'
212 | }
213 | })
214 |
215 | // 删除缓存
216 | delete cacheDownItem[url]
217 | cacheItem = null
218 | item = null
219 | })
220 |
221 | // 恢复
222 | if (item.canResume) {
223 | item.resume()
224 | }
225 | } catch (error) {
226 | console.log(error)
227 | }
228 | })
229 |
230 | // 暂停所有下载任务
231 | const cacheDownItemClose = () => {
232 | for (const key in cacheDownItem) {
233 | // eslint-disable-next-line no-prototype-builtins
234 | if (cacheDownItem.hasOwnProperty(key)) {
235 | const element = cacheDownItem[key]
236 | if (element._downFileItem) {
237 | element._downFileItem.pause()
238 | element._downFileItem = null
239 | }
240 | }
241 | }
242 | }
243 |
244 | app.on('gpu-process-crashed', function() {
245 | cacheDownItemClose()
246 | })
247 |
248 | app.on('renderer-process-crashed', function() {
249 | cacheDownItemClose()
250 | })
251 |
252 | let noti
253 | const notification = (url) => {
254 | noti = new Notification({
255 | title: '下载成功',
256 | bodyString: url,
257 | silentBoolean: false,
258 | icon: url
259 | })
260 | noti.show()
261 | noti.once('click', () => {
262 | shell.showItemInFolder(url)
263 | })
264 | }
265 | }
266 |
267 | module.exports = {
268 | mainWindowIpcStart
269 | }
270 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 | import router from './router'
4 | import './permission'
5 | import '@/assets/reset.css'
6 | import '@/assets/font/iconfont.css'
7 | import Element from '@/utils/ElementUI'
8 | import store from '@/store'
9 |
10 | import { getTime, byte, getImgCollection, updImgCollection, getDownFiles, getDownDoneFiles, updDownFiles, updDownDoneFiles } from '@/utils/util'
11 | import { downFile, updateDownState, initPath } from '@/utils/FileTool'
12 |
13 | import 'core-js/stable'
14 | import 'regenerator-runtime/runtime'
15 |
16 | import 'element-ui/lib/theme-chalk/base.css'
17 | import 'element-ui/lib/theme-chalk/index.css'
18 | Vue.use(Element)
19 |
20 | Vue.filter('byte', byte)
21 |
22 | Vue.config.productionTip = false
23 |
24 | initPath()
25 |
26 | new Vue({
27 | data() {
28 | return {
29 | // 收藏
30 | collections: getImgCollection(),
31 | // 下载列表
32 | downFiles: getDownFiles(),
33 | downDoneFiles: getDownDoneFiles()
34 | }
35 | },
36 | watch: {
37 | collections: {
38 | deep: true,
39 | handler(val) {
40 | updImgCollection(val)
41 | }
42 | },
43 | downFiles: {
44 | deep: true,
45 | handler(val) {
46 | updDownFiles(val)
47 | }
48 | },
49 | downDoneFiles: {
50 | deep: true,
51 | handler(val) {
52 | updDownDoneFiles(val)
53 | }
54 | }
55 | },
56 | created() {
57 | updateDownState(this.updateDownState)
58 | },
59 | methods: {
60 | // 添加收藏
61 | AddCollection(obj) {
62 | if (obj) this.collections.splice(0, 0, obj)
63 | },
64 | // 移除收藏
65 | removeCollection(obj) {
66 | const index = this.collections.findIndex(item => item.id === obj.id)
67 | if (index > -1) {
68 | this.collections.splice(index, 1)
69 | }
70 | },
71 | // 下载文件
72 | addDownFile(obj) {
73 | const index = this.downFiles.findIndex(item => item.f_id === obj.f_id)
74 | if (index === -1) {
75 | obj.progress = 0
76 | obj.speedBytes = 0
77 | obj.state = 'wait'
78 | obj.done = 'downing'
79 | this.downFiles.splice(0, 0, obj)
80 | console.log(obj)
81 | downFile(obj)
82 | }
83 | },
84 | // 更新状态
85 | updateDownState(data) {
86 | this.$nextTick(() => {
87 | const { f_id, done, progress } = data
88 | const index = this.downFiles.findIndex(item => item.f_id === f_id)
89 | if (done === 'end') {
90 | if (progress === 100) {
91 | const { f_id, path } = data
92 | this.downDoneFiles.splice(0, 0, { f_id, path, downloadtime: getTime() })
93 | if (index > -1) this.downFiles.splice(index, 1)
94 | }
95 | } else {
96 | if (index > -1) this.$set(this.downFiles, index, data)
97 | }
98 | })
99 | },
100 | // 删除下载列表
101 | removeDownFile(id, downing) {
102 | if (downing) {
103 | const index = this.downFiles.findIndex(item => item.f_id === id)
104 | if (index > -1) {
105 | this.downFiles.splice(index, 1)
106 | }
107 | } else {
108 | const index = this.downDoneFiles.findIndex(item => item.f_id === id)
109 | if (index > -1) {
110 | this.downDoneFiles.splice(index, 1)
111 | }
112 | }
113 | }
114 | },
115 | router,
116 | store,
117 | render: h => h(App)
118 | }).$mount('#app')
119 |
--------------------------------------------------------------------------------
/src/pages/404/404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 | 返回上一页
7 |
8 |
9 |
10 |
11 |
16 |
17 |
29 |
--------------------------------------------------------------------------------
/src/pages/CompleteTransfer/CompleteTransfer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/src/pages/Hide/Hide.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 隐藏空间
4 |
5 |
6 |
7 |
16 |
17 |
20 |
--------------------------------------------------------------------------------
/src/pages/Home/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
15 |
16 | -
22 |
23 |
{{ grouped }}
24 |
25 |
26 | -
34 |
35 | {{ item.f_name }}
36 |
37 |
38 |
43 |
44 |
45 |
46 |
47 | -
48 |
49 |
50 |
54 |
55 |
56 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 | -
76 |
77 |
78 |
79 |
80 |
81 |
![]()
82 |
{{ file.f_name }}
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | {{ fTime(file) }}
94 |
95 |
96 | {{ fileSize(file) }}
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | 文件夹名:
112 |
113 |
114 |
115 | 确定
116 | 取消
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
346 |
347 |
456 |
--------------------------------------------------------------------------------
/src/pages/Home/components/FileButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
46 |
47 |
69 |
--------------------------------------------------------------------------------
/src/pages/Home/components/FunctionColumn.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 返回上个文件夹
5 | 上传
6 | 下载
7 | 分享
8 | 删除
9 | 新建文件夹
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
96 |
97 |
152 |
--------------------------------------------------------------------------------
/src/pages/Home/components/fileUpload.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
49 |
50 |
52 |
--------------------------------------------------------------------------------
/src/pages/Index/Index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
22 |
23 |
32 |
--------------------------------------------------------------------------------
/src/pages/Index/component/AppMain/AppMain.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
32 |
33 |
44 |
--------------------------------------------------------------------------------
/src/pages/Index/component/AppMain/component/HistoricalRecords.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
19 | {{ tag.meta.title }}
20 |
21 |
22 |
28 |
29 |
30 |
31 |
32 |
135 |
136 |
208 |
--------------------------------------------------------------------------------
/src/pages/Index/component/IndexLeft/IndexLeft.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
34 |
35 |
36 |
37 |
144 |
145 |
160 |
--------------------------------------------------------------------------------
/src/pages/Index/component/IndexTop/IndexTop.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | logo
8 |
9 |
10 |
23 |
24 |
25 |
26 |
{{ userInfo.u_name }}
27 |
注销
28 |
29 |
30 |
31 |
32 |
33 |
34 |
104 |
105 |
150 |
--------------------------------------------------------------------------------
/src/pages/Login/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 登录
5 |
6 |
7 |
17 |
18 |
19 |
20 |
30 |
31 |
32 |
登录
37 |
38 |
没有账号?立即申请
39 |
忘记密码
40 |
41 |
42 |
43 |
44 |
45 |
46 |
118 |
119 |
195 |
--------------------------------------------------------------------------------
/src/pages/RecycleBin/RecycleBin.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
43 |
44 |
47 |
--------------------------------------------------------------------------------
/src/pages/Redirect/index.vue:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/pages/Search/Search.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 搜索资源
4 |
5 |
6 |
7 |
12 |
13 |
16 |
--------------------------------------------------------------------------------
/src/pages/Share/Share.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 分享空间
4 |
5 |
6 |
7 |
13 |
14 |
17 |
--------------------------------------------------------------------------------
/src/pages/TransferList/TransferList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
12 |
13 |
14 | 修改下载目录
15 |
16 |
17 | 全部开始
18 | 全部取消
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
60 |
61 |
86 |
--------------------------------------------------------------------------------
/src/pages/TransferList/components/uploadList.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
![]()
6 |
7 |
{{ file.fileName }}
8 |
9 |
10 |
文件大小:{{ fileSize(file.fileSize) }}
11 |
下载速度:{{ file.uploadSpeed }}/s
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
56 |
97 |
--------------------------------------------------------------------------------
/src/pages/applicationAccount/applicationAccount.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
返回登录页
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
21 |
22 |
29 |
30 |
31 |
32 |
38 |
39 |
40 |
41 | 提交完成,正在等管理员审核,请留意您的邮箱。
42 |
43 |
{{ stepCount === 3 ? '返回登录页' : '下一步' }}
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
188 |
189 |
198 |
--------------------------------------------------------------------------------
/src/permission.js:
--------------------------------------------------------------------------------
1 | import NProgress from 'nprogress'
2 | import 'nprogress/nprogress.css'
3 | import router from './router'
4 | import { getToken } from './utils/tokne'
5 | import store from './store'
6 |
7 | const whiteList = ['/login', '/app-account']
8 | router.beforeEach(async(to, form, next) => {
9 | const token = getToken()
10 | NProgress.start()
11 | if (token) {
12 | if (to.path === '/login') { return next({ path: '/' }) }
13 | if (JSON.stringify(store.getters.userInfo) !== '{}') { return next() }
14 | try {
15 | await store.dispatch('getInfo')
16 | store.dispatch('setCurrentPath', {
17 | path: store.getters.userInfo.u_name,
18 | u_id: store.getters.userInfo.u_id
19 | })
20 | next()
21 | } catch (e) {
22 | await store.dispatch('resetToken')
23 | this.$message({
24 | type: 'error',
25 | message: 'token失效'
26 | })
27 | next(`/login?redirect=${to.path}`)
28 | }
29 | } else {
30 | whiteList.indexOf(to.path) !== -1 ? next() : next(`/login?redirect=${to.path}`)
31 | }
32 | NProgress.done()
33 | })
34 |
35 | router.afterEach(() => {
36 | NProgress.done()
37 | })
38 |
--------------------------------------------------------------------------------
/src/router/_import_development.js:
--------------------------------------------------------------------------------
1 | module.exports = file => require('@/pages/' + file + '.vue').default
2 |
--------------------------------------------------------------------------------
/src/router/_import_production.js:
--------------------------------------------------------------------------------
1 | module.exports = file => () => import('@/pages/' + file + '.vue')
2 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Router from 'vue-router'
2 | import Vue from 'vue'
3 | const _import = require('./_import_' + process.env.NODE_ENV)
4 |
5 | Vue.use(Router)
6 |
7 | import Index from '@/pages/Index/Index'
8 |
9 | export default new Router({
10 | routes: [
11 | {
12 | path: '/redirect',
13 | component: Index,
14 | children: [
15 | {
16 | path: '/redirect/:path(.*)',
17 | component: _import('Redirect/index')
18 | }
19 | ]
20 | },
21 |
22 | {
23 | path: '/',
24 | component: Index,
25 | children: [
26 | {
27 | path: '/',
28 | component: _import('Home/Home'),
29 | name: 'Index',
30 | meta: {
31 | title: '我的网盘'
32 | }
33 | }
34 | ]
35 | },
36 |
37 | {
38 | path: '/transfer',
39 | component: Index,
40 | children: [
41 | {
42 | path: '/transfer/:key',
43 | component: _import('TransferList/TransferList'),
44 | name: 'TransferList',
45 | meta: {
46 | title: '传输列表'
47 | }
48 | }
49 | ]
50 | },
51 |
52 | {
53 | path: '/complete-transfer',
54 | component: Index,
55 | children: [
56 | {
57 | path: '/complete-transfer',
58 | component: _import('CompleteTransfer/CompleteTransfer'),
59 | name: 'CompleteTransfer',
60 | meta: {
61 | title: '完成传输'
62 | }
63 | }
64 | ]
65 | },
66 |
67 | {
68 | path: '/search',
69 | component: Index,
70 | children: [
71 | {
72 | path: '/search',
73 | component: _import('Search/Search'),
74 | name: 'Search',
75 | meta: {
76 | title: '找资源'
77 | }
78 | }
79 | ]
80 | },
81 |
82 | {
83 | path: '/hide',
84 | component: Index,
85 | children: [
86 | {
87 | path: '/hide',
88 | component: _import('Hide/Hide'),
89 | name: 'Hide',
90 | meta: {
91 | title: '隐藏空间'
92 | }
93 | }
94 | ]
95 | },
96 |
97 | {
98 | path: '/share',
99 | component: Index,
100 | children: [
101 | {
102 | path: '/share',
103 | component: _import('Share/Share'),
104 | name: 'Share',
105 | meta: {
106 | title: '分享空间'
107 | }
108 | }
109 | ]
110 | },
111 |
112 | {
113 | path: '/recycle',
114 | component: Index,
115 | children: [
116 | {
117 | path: '/recycle',
118 | component: _import('RecycleBin/RecycleBin'),
119 | name: 'RecycleBin',
120 | meta: {
121 | title: '回收站'
122 | }
123 | }
124 | ]
125 | },
126 |
127 | {
128 | path: '/login',
129 | name: 'login',
130 | component: _import('Login/Login')
131 | },
132 |
133 | {
134 | path: '/app-account',
135 | name: 'applicationAccount',
136 | component: _import('applicationAccount/applicationAccount')
137 | },
138 |
139 | {
140 | path: '*',
141 | component: _import('404/404')
142 | }
143 | ]
144 | })
145 |
146 |
--------------------------------------------------------------------------------
/src/store/getters.js:
--------------------------------------------------------------------------------
1 | export default {
2 | token: state => state.user.token,
3 | userInfo: state => state.user.userInfo,
4 | historyList: state => state.history.historyList,
5 | cachedViews: state => state.history.cachedViews,
6 | uploadInfo: state => state.upload.uploadList,
7 | fileList: state => state.file.fileList,
8 | fileCurrentPath: state => state.file.fileCurrentPath
9 | }
10 |
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Vuex from 'vuex'
3 |
4 | Vue.use(Vuex)
5 |
6 | import getters from './getters'
7 |
8 | const modulesFiles = require.context('./modules', true, /\.js$/)
9 |
10 | const modules = modulesFiles.keys().reduce((modules, modulePath) => {
11 | const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
12 | const value = modulesFiles(modulePath)
13 | modules[moduleName] = value.default
14 | return modules
15 | }, {})
16 |
17 | export default new Vuex.Store({
18 | modules,
19 | getters
20 | })
21 |
--------------------------------------------------------------------------------
/src/store/modules/file.js:
--------------------------------------------------------------------------------
1 | import { uploadList, groupingList, getHistory } from '@/api/file'
2 | const state = {
3 | fileList: [],
4 | fileHistory: [],
5 | fileCurrentPath: ''
6 | }
7 |
8 | const actions = {
9 | getFileList({ commit, state }, u_id) {
10 | return new Promise(resolve => {
11 | uploadList(u_id, state.fileCurrentPath).then(res => {
12 | commit('GET_FILE_LIST', res.data)
13 | resolve(res.data)
14 | }).catch(() => {
15 | commit('GET_FILE_LIST', [])
16 | })
17 | })
18 | },
19 |
20 | getHistory({ commit }) {
21 | return new Promise(resolve => {
22 | getHistory().then(res => {
23 | commit('GET_HISTORY', res.data)
24 | resolve(res.data)
25 | })
26 | })
27 | },
28 |
29 | setCurrentPath({ commit, dispatch }, options) {
30 | const { path, u_id } = options
31 | commit('SET_CURRENT_PATH', path)
32 | dispatch('getFileList', u_id)
33 | // dispatch('setBackPath', options)
34 | },
35 |
36 | setBackPath({ commit, dispatch }, options) {
37 | return new Promise(resolve => {
38 | const { path, u_id } = options
39 | commit('SET_BACK_PATH', path)
40 | dispatch('getGroupList').then(list => {
41 | resolve(list)
42 | })
43 | dispatch('getFileList', u_id)
44 | })
45 | },
46 |
47 | getGroupList({ state }) {
48 | return new Promise(resolve => {
49 | groupingList(state.fileCurrentPath).then(res => {
50 | resolve(res.data)
51 | })
52 | })
53 | },
54 |
55 | filterFile({ commit }, list) {
56 | commit('FILTER_FILE_LIST', list)
57 | }
58 | }
59 |
60 | const mutations = {
61 | GET_FILE_LIST: (state, list) => {
62 | state.fileList = list
63 | },
64 |
65 | GET_HISTORY: (state, list) => {
66 | state.fileHistory = list
67 | },
68 |
69 | SET_BACK_PATH: (state, path) => {
70 | state.fileCurrentPath = path
71 | },
72 |
73 | FILTER_FILE_LIST: (state, list) => {
74 | state.fileList = list
75 | },
76 |
77 | SET_CURRENT_PATH: (state, path) => {
78 | state.fileCurrentPath = !state.fileCurrentPath ? path : `${state.fileCurrentPath}/${path}`
79 | }
80 | }
81 |
82 | export default {
83 | state,
84 | actions,
85 | mutations
86 | }
87 |
--------------------------------------------------------------------------------
/src/store/modules/history.js:
--------------------------------------------------------------------------------
1 |
2 | const state = {
3 | historyList: [],
4 | cachedViews: []
5 | }
6 |
7 | const actions = {
8 | addRouter({ dispatch }, router) {
9 | dispatch('setHistory', router)
10 | dispatch('addCachedView', router)
11 | },
12 |
13 | delRouter({ dispatch, state }, router) {
14 | return new Promise((resolve) => {
15 | dispatch('delCachedView', router)
16 | dispatch('delHistory', router)
17 | resolve({
18 | historyList: [...state.historyList],
19 | cachedViews: [...state.cachedViews]
20 | })
21 | })
22 | },
23 |
24 | setHistory({ commit }, router) {
25 | commit('SET_HISTORY', router)
26 | },
27 |
28 | addCachedView({ commit }, router) {
29 | commit('ADD_CACHED_VIEW', router)
30 | },
31 |
32 | delCachedView({ commit, state }, router) {
33 | return new Promise((resolve) => {
34 | commit('DEL_CACHED_VIEW', router)
35 | resolve([...state.cachedViews])
36 | })
37 | },
38 |
39 | delHistory({ commit, state }, router) {
40 | return new Promise((resolve) => {
41 | commit('DEL_HISTORY', router)
42 | resolve([...state.historyList])
43 | })
44 | },
45 |
46 | delOtherHistory({ dispatch }, router) {
47 | dispatch('delOtherHistoryList', router)
48 | dispatch('delOtherCachedViews', router)
49 | },
50 |
51 | delOtherHistoryList({ commit }, router) {
52 | commit('DEL_OTHER_HISTORY_LIST', router)
53 | },
54 |
55 | delOtherCachedViews({ commit }, router) {
56 | commit('DEL_OTHER_CACHED_VIEW', router)
57 | },
58 |
59 | delAllHistory({ commit, state }) {
60 | return new Promise(resolve => {
61 | commit('DEL_ALL_HISTORY')
62 | resolve({
63 | historyList: [...state.historyList]
64 | })
65 | })
66 | }
67 |
68 | }
69 |
70 | const mutations = {
71 | SET_HISTORY: (state, router) => {
72 | !state.historyList.some(r => r.path === router.path) && (state.historyList = [...state.historyList, router])
73 | },
74 |
75 | DEL_HISTORY: (state, router) => {
76 | state.historyList.forEach((v, i) => {
77 | console.log(1)
78 | if (v.path === router.path) {
79 | return state.historyList.splice(i, 1)
80 | }
81 | })
82 | },
83 |
84 | ADD_CACHED_VIEW: (state, router) => {
85 | !state.cachedViews.includes(router.name) && (state.cachedViews = [...state.cachedViews, router.name])
86 | },
87 |
88 | DEL_CACHED_VIEW: (state, router) => {
89 | const index = state.cachedViews.indexOf(router.name)
90 | index > -1 && state.cachedViews.splice(index, 1)
91 | },
92 |
93 | DEL_OTHER_HISTORY_LIST: (state, router) => {
94 | state.historyList = state.historyList.filter(r => (r.path === router.path))
95 | },
96 |
97 | DEL_OTHER_CACHED_VIEW: (state, router) => {
98 | const index = state.cachedViews.indexOf(router.name)
99 | state.cachedViews = index > -1 ? state.cachedViews.slice(index, index + 1) : []
100 | },
101 |
102 | DEL_ALL_HISTORY: state => {
103 | state.cachedViews = []
104 | state.historyList = []
105 | }
106 |
107 | }
108 |
109 | export default {
110 | state,
111 | actions,
112 | mutations
113 | }
114 |
--------------------------------------------------------------------------------
/src/store/modules/navList.js:
--------------------------------------------------------------------------------
1 |
2 | const state = {
3 | navType: null
4 | }
5 |
6 | const actions = {
7 | switchMode({ commit }, type) {
8 | commit('SWITCH_MODE', type)
9 | }
10 | }
11 |
12 | const mutations = {
13 | SWITCH_MODE: (state, type) => {
14 | state.navType = type
15 | }
16 | }
17 |
18 | export default {
19 | state,
20 | actions,
21 | mutations
22 | }
23 |
--------------------------------------------------------------------------------
/src/store/modules/upload.js:
--------------------------------------------------------------------------------
1 | const state = {
2 | initFile: {
3 | progressBar: 0,
4 | sloaded: 0,
5 | dloadedremainingTime: null,
6 | uploadSpeed: null,
7 | fileName: '',
8 | fileSize: 0,
9 | fileType: ''
10 | },
11 | uploadList: []
12 | }
13 |
14 | const mutations = {
15 | ON_UPLOAD_PROGRESS: (state, options) => {
16 | state.uploadList.map((c, i) => {
17 | c.fileName === options.fileName ? (
18 | state.uploadList[i] = { ...c, ...options }
19 | ) : (
20 | state.uploadList = [
21 | ...state.uploadList,
22 | options
23 | ]
24 | )
25 | })
26 | },
27 |
28 | RESET_PROGRESS: (state) => {
29 | state.uploadList = []
30 | }
31 | }
32 |
33 | const actions = {
34 | onUploadProgress({ commit }, options) {
35 | commit('ON_UPLOAD_PROGRESS', options)
36 | },
37 |
38 | resetProgress({ commit }) {
39 | commit('RESET_PROGRESS')
40 | }
41 | }
42 |
43 | export default {
44 | state,
45 | mutations,
46 | actions
47 | }
48 |
--------------------------------------------------------------------------------
/src/store/modules/user.js:
--------------------------------------------------------------------------------
1 | import { login, getUserInfo } from '../../api/user'
2 | import { setToken, removeToken, getToken } from '../../utils/tokne'
3 |
4 | const state = {
5 | token: getToken(),
6 | userInfo: {}
7 | }
8 |
9 | const actions = {
10 | login({ commit }, options) {
11 | return new Promise((resolve, reject) => {
12 | login(options).then(res => {
13 | const { data } = res
14 | commit('SET_TOKEN', data.token)
15 | setToken(data.token)
16 | resolve()
17 | }).catch(error => {
18 | reject(error)
19 | })
20 | })
21 | },
22 |
23 | getInfo({ commit }) {
24 | return new Promise(resolve => {
25 | getUserInfo().then(res => {
26 | commit('SET_USER_INFO', res.data)
27 | resolve(res)
28 | })
29 | })
30 | },
31 |
32 | resetToken({ commit }) {
33 | return new Promise(resolve => {
34 | commit('SET_TOKEN', '')
35 | commit('SET_USER_INFO', {})
36 | removeToken()
37 | resolve()
38 | })
39 | }
40 | }
41 |
42 | const mutations = {
43 | SET_TOKEN: (state, token) => {
44 | state.token = token
45 | },
46 |
47 | SET_USER_INFO(state, userInfo) {
48 | state.userInfo = userInfo
49 | }
50 | }
51 |
52 | export default {
53 | state,
54 | actions,
55 | mutations
56 | }
57 |
--------------------------------------------------------------------------------
/src/utils/ElementUI.js:
--------------------------------------------------------------------------------
1 |
2 | import {
3 | Message,
4 | Button,
5 | Input,
6 | Form,
7 | FormItem,
8 | Step,
9 | Steps,
10 | Menu,
11 | MenuItem,
12 | MenuItemGroup,
13 | Submenu,
14 | Avatar,
15 | Checkbox,
16 | CheckboxGroup,
17 | Col,
18 | Row,
19 | Progress,
20 | Upload,
21 | Table,
22 | CheckboxButton,
23 | TableColumn,
24 | Radio,
25 | Link
26 | } from 'element-ui'
27 |
28 | const element = {
29 | install(Vue) {
30 | Vue.use(Button)
31 | Vue.use(Input)
32 | Vue.use(Form)
33 | Vue.use(FormItem)
34 | Vue.use(Step)
35 | Vue.use(Steps)
36 | Vue.use(Menu)
37 | Vue.use(MenuItem)
38 | Vue.use(Submenu)
39 | Vue.use(Avatar)
40 | Vue.use(MenuItemGroup)
41 | Vue.use(Checkbox)
42 | Vue.use(CheckboxGroup)
43 | Vue.use(Col)
44 | Vue.use(Row)
45 | Vue.use(Progress)
46 | Vue.use(Table)
47 | Vue.use(CheckboxButton)
48 | Vue.use(TableColumn)
49 | Vue.use(Upload)
50 | Vue.use(Radio)
51 | Vue.use(Link)
52 | Vue.prototype.$message = Message
53 | }
54 | }
55 |
56 | export default element
57 |
--------------------------------------------------------------------------------
/src/utils/FileTool.js:
--------------------------------------------------------------------------------
1 | import store from '../store'
2 | import config from './config'
3 |
4 | // eslint-disable-next-line no-undef
5 | const { ipcRenderer } = __non_webpack_require__('electron')
6 |
7 | export function fileTraversal(list, cb) {
8 | list.forEach((item, index) => {
9 | cb && cb(item, index)
10 | })
11 | }
12 |
13 | export function dowUrl(url) {
14 | const path = 'http://localhost:3000/'
15 | return `${path}${url}`
16 | }
17 |
18 | export async function fileTypeFilter(type) {
19 | await store.dispatch('getFileList', store.getters.userInfo.u_id).then(data => {
20 | let filterFileList = []
21 | if (type === 'qita') {
22 | const wilteList = ['rar', 'ptf', 'zip']
23 | const typeList = Object.keys(config.FILE_TYPE)
24 | data.forEach(f => {
25 | const fileType = f.f_name.split('.')[1]
26 | ;(wilteList.includes(fileType) || !typeList.includes(fileType)) && (
27 | filterFileList = [
28 | ...filterFileList,
29 | f
30 | ]
31 | )
32 | })
33 | } else {
34 | filterFileList = data.filter(file => type.includes(file.f_name.split('.')[1]))
35 | }
36 | store.dispatch('filterFile', filterFileList)
37 | })
38 | }
39 |
40 | export function fomartPath(pathArr) {
41 | let path = ''
42 | if (pathArr.length > 1) {
43 | pathArr.forEach(item => {
44 | path += `${item}/`
45 | })
46 | path = path.substring(0, path.length - 1)
47 | } else {
48 | path = pathArr[0]
49 | }
50 | return path
51 | }
52 |
53 | /**
54 | * 下载文件
55 | * @param {*} obj
56 | */
57 | export const downFile = (obj) => {
58 | ipcRenderer.send('down-file', obj)
59 |
60 | /* return new Promise((resolve, reject) => {
61 | ipcRenderer.once(`down-file-${obj.id}`, (e, data) => resolve(data))
62 | }) */
63 | }
64 |
65 | /**
66 | * 更新下载状态
67 | * @param {*} cb
68 | */
69 | export const updateDownState = (cb) => {
70 | ipcRenderer.on('update-down-state', function(e, data) {
71 | cb(data)
72 | })
73 | }
74 |
75 | /**
76 | * 暂停下载
77 | * @param {*} url
78 | */
79 | export const pause = (url) => {
80 | ipcRenderer.send('down-file-pause', { url })
81 | }
82 |
83 | /**
84 | * 取消下载
85 | * @param {*} url
86 | */
87 | export const cancel = (url) => {
88 | return new Promise((resolve, reject) => {
89 | ipcRenderer.send('down-file-cancel', { url })
90 | ipcRenderer.once(`down-file-cancel-${url}`, (e, data) => resolve(data))
91 | })
92 | }
93 |
94 | /**
95 | * 恢复下载
96 | * @param {*} url
97 | */
98 | export const resume = (url) => {
99 | return new Promise((resolve, reject) => {
100 | ipcRenderer.send('down-file-resume', { url })
101 | ipcRenderer.once(`down-file-resume-${url}`, (e, data) => resolve(data))
102 | })
103 | }
104 |
105 | /**
106 | * 断点续下载
107 | * @param {*} obj
108 | */
109 | export const nextresume = (obj) => {
110 | return new Promise((resolve, reject) => {
111 | ipcRenderer.send('resume-download', obj)
112 | ipcRenderer.once(`resume-download-${obj.id}`, (e, data) => resolve(data))
113 | })
114 | }
115 |
116 | /**
117 | * 初始化下载地址
118 | * @param {*} path 下载路径
119 | */
120 | export const initPath = () => {
121 | const path = localStorage.getItem('downloads') || 'not'
122 | ipcRenderer.send('set_path', { path })
123 | ipcRenderer.once(`set_path`, (e, data) => {
124 | localStorage.setItem('downloads', data)
125 | })
126 | }
127 |
--------------------------------------------------------------------------------
/src/utils/config.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | FILE_TYPE: {
4 | zip: require('@/assets/images/zip.png'),
5 | rar: require('@/assets/images/zip.png'),
6 | png: require('@/assets/images/img.png'),
7 | jpg: require('@/assets/images/img.png'),
8 | jpeg: require('@/assets/images/img.png'),
9 | avi: require('@/assets/images/avi.png'),
10 | mp3: require('@/assets/images/mp3.png'),
11 | ptf: require('@/assets/images/ppt.png'),
12 | word: require('@/assets/images/word.png'),
13 | excel: require('@/assets/images/excel.png'),
14 | mp4: require('@/assets/images/mp3.png'),
15 | qita: require('@/assets/images/qita.png')
16 | },
17 |
18 | transfer: [
19 | { key: '1', icon: 'el-icon-download', title: '正在下载' },
20 | { key: '2', icon: 'el-icon-upload2', title: '正在上传' },
21 | { key: '3', icon: 'el-icon-circle-check', title: '完成传输' }
22 | ],
23 |
24 | home: [
25 | { key: '1', icon: 'el-icon-time', title: '最近文件' },
26 | { key: '2', icon: 'el-icon-tickets', title: '全部文件', children: [
27 | { key: '2-1', title: '图片' },
28 | { key: '2-2', title: '视频' },
29 | { key: '2-3', title: '文档' },
30 | { key: '2-4', title: '表格' },
31 | { key: '2-5', title: '音乐' },
32 | { key: '2-6', title: '其他' }
33 | ] },
34 | { key: '3', icon: 'el-icon-lock', title: '隐藏空间' },
35 | { key: '4', icon: 'el-icon-share', title: '我的分享' },
36 | { key: '5', icon: 'el-icon-delete', title: '回收站' }
37 | ],
38 |
39 | share: ''
40 | }
41 |
--------------------------------------------------------------------------------
/src/utils/publicTool.js:
--------------------------------------------------------------------------------
1 | import config from './config'
2 |
3 | export function goRouter(Vue, path, params = null) {
4 | const routerPath = params ? `${path}/${params}` : path;
5 | (Vue.$router.history.current.path !== path) && Vue.$router.push(routerPath)
6 | }
7 |
8 | export function fileType(fileName) {
9 | const fileType = fileName.split('.')[1]
10 | const iconKey = Object.keys(config.FILE_TYPE).find(key => key === fileType) || 'qita'
11 | return config.FILE_TYPE[iconKey]
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/src/utils/request.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import store from '@/store'
3 | import { Message } from 'element-ui'
4 | import { getToken } from './tokne'
5 |
6 | const service = axios.create({
7 | baseURL: process.env.VUE_APP_BASE_API,
8 | timeout: 1000000
9 | })
10 |
11 | service.interceptors.request.use(
12 | config => {
13 | config.headers['Content-Type'] = 'application/json;charset=UTF-8'
14 | store.getters.token && (config.headers['Authorization'] = `Bearer ${getToken()}`)
15 | return config
16 | },
17 | error => {
18 | Message({
19 | message: error || '网络错误',
20 | duration: 1000,
21 | type: 'error'
22 | })
23 | return Promise.reject(error)
24 | }
25 | )
26 |
27 | service.interceptors.response.use(
28 | response => {
29 | const res = response.data || response
30 | const errMsg = res.msg || '请求失败!'
31 | if (res.code && res.code !== 200) {
32 | Message({
33 | message: errMsg || '请求失败',
34 | duration: 1000,
35 | type: 'error'
36 | })
37 | return Promise.reject('error')
38 | } else {
39 | return Promise.resolve(res)
40 | }
41 | },
42 | error => {
43 | if (error.request.status === 401) { store.dispatch('resetToken') }
44 | Message({
45 | message: error || '请求失败',
46 | duration: 1000,
47 | type: 'error'
48 | })
49 | return Promise.reject(error)
50 | }
51 | )
52 |
53 | export default service
54 |
--------------------------------------------------------------------------------
/src/utils/tokne.js:
--------------------------------------------------------------------------------
1 |
2 | import Cookies from 'js-cookie'
3 |
4 | const TOKEN_KEY = 'TOKEN_KEY'
5 |
6 | export function getToken() {
7 | return Cookies.get(TOKEN_KEY)
8 | }
9 |
10 | export function removeToken() {
11 | return Cookies.remove(TOKEN_KEY)
12 | }
13 |
14 | export function setToken(token) {
15 | return Cookies.set(TOKEN_KEY, token)
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/util.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 获取时间 yyyy-MM-dd hh:mm:ss
3 | */
4 | export const getTime = () => {
5 | const date = new Date()
6 | return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`
7 | }
8 |
9 | /**
10 | * 存储单位换算
11 | * @param {*} bytes
12 | */
13 | export const byte = (bytes) => {
14 | if (bytes === 0) return '0 B'
15 | var k = 1000 // or 1024
16 | var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
17 | var i = Math.floor(Math.log(bytes) / Math.log(k))
18 |
19 | return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i]
20 | }
21 |
22 | /**
23 | * 防抖
24 | * @param {*} fn
25 | * @param {*} wait 延迟时间 默认1秒
26 | */
27 | export const debounce = (fn, wait = 1000) => {
28 | let timeout = null
29 | return function(key, val) {
30 | if (timeout !== null) clearTimeout(timeout)
31 | timeout = setTimeout(() => {
32 | fn(key, val)
33 | }, wait)
34 | }
35 | }
36 |
37 | /**
38 | * 获取 localStorage
39 | * @param {*} key key
40 | * @param {*} val 默认值
41 | */
42 | export const getData = (key, val = []) => {
43 | const data = localStorage.getItem(key)
44 | if (data) {
45 | return JSON.parse(data)
46 | }
47 | return val
48 | }
49 |
50 | /**
51 | * 设置 localStorage
52 | * @param {*} key key
53 | * @param {*} val value
54 | */
55 | export const setData = (key, val) => localStorage.setItem(key, JSON.stringify(val))
56 |
57 | /**
58 | * 获取收藏数据
59 | */
60 | export const getImgCollection = () => getData('ImgCollection')
61 |
62 | /**
63 | * 更新收藏列表
64 | * @param {*} arr
65 | */
66 | export const updImgCollection = (arr) => setData('ImgCollection', arr)
67 |
68 | /**
69 | * 获取下载数据
70 | */
71 | export const getDownFiles = () => getData('DownFiles')
72 |
73 | /**
74 | * 更新下载列表
75 | * @param {*} arr
76 | */
77 | const _updDownFiles = debounce(setData, 1000)
78 | export const updDownFiles = (arr) => {
79 | _updDownFiles('DownFiles', arr)
80 | }
81 |
82 | /**
83 | * 获取下载完成数据
84 | */
85 | export const getDownDoneFiles = () => getData('DownDoneFiles')
86 |
87 | /**
88 | * 更新下载完成列表
89 | * @param {*} arr
90 | */
91 | const _updDownDoneFiles = debounce(setData, 1000)
92 | export const updDownDoneFiles = (arr) => _updDownDoneFiles('DownDoneFiles', arr)
93 |
94 | /**
95 | * obj 转 url
96 | * @param {*} obj
97 | */
98 | export const objToUrl = (obj = {}) => {
99 | let str = ''
100 | for (const key in obj) {
101 | // eslint-disable-next-line no-prototype-builtins
102 | if (obj.hasOwnProperty(key)) {
103 | if (key === 'purity') {
104 | if (obj[key].length === 2) {
105 | str += `&${key}=111`
106 | } else if (obj[key][0] === 'SFW') {
107 | str += `&${key}=100`
108 | } else {
109 | str += `&${key}=010`
110 | }
111 | } else if (obj[key] !== '') {
112 | str += `&${key}=${obj[key]}`
113 | }
114 | }
115 | }
116 | return str
117 | }
118 |
119 | /**
120 | * 图片宽高比适应
121 | * @param {*} w 容器宽
122 | * @param {*} h 容器高
123 | * @param {*} r 图片宽高比
124 | */
125 | export const aspectRatioToWH = (w, h, r, iw, ih) => {
126 | const _r = w / h
127 | if (iw < w && ih < h) {
128 | return { w: iw, h: ih }
129 | }
130 | // 容器宽度比 大=于 内容 宽高比 以高度为基准
131 | if (_r > r) {
132 | return {
133 | w: h * r, h
134 | }
135 | } else if (_r < r) {
136 | return {
137 | w, h: w / r
138 | }
139 | } else {
140 | return {
141 | w, h
142 | }
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | publicPath: './',
4 | transpileDependencies: [/node_modules[/\\\\](element-ui|vuex|)[/\\\\]/],
5 | }
6 |
--------------------------------------------------------------------------------