@sugarat/easypicker2-client 2.4.3 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/dist/assets/aria-bc8e8b0f.js +2 -0
  2. package/dist/assets/aria-bc8e8b0f.js.map +1 -0
  3. package/dist/assets/aria-legacy.af0825d3.js +2 -0
  4. package/dist/assets/data-analysis-3ce8c1c1.js +2 -0
  5. package/dist/assets/data-analysis-3ce8c1c1.js.map +1 -0
  6. package/dist/assets/data-analysis-legacy.985137a1.js +2 -0
  7. package/dist/assets/data-board-fc2c2ec1.js +2 -0
  8. package/dist/assets/data-board-fc2c2ec1.js.map +1 -0
  9. package/dist/assets/data-board-legacy.33116f7c.js +2 -0
  10. package/dist/assets/el-date-picker-b377a533.js +2 -0
  11. package/dist/assets/el-date-picker-b377a533.js.map +1 -0
  12. package/dist/assets/el-date-picker-cf2e83b6.css +1 -0
  13. package/dist/assets/el-date-picker-legacy.127f0787.js +2 -0
  14. package/dist/assets/el-dialog-25bd2fb8.css +1 -0
  15. package/dist/assets/el-dialog-5b7bce58.js +2 -0
  16. package/dist/assets/el-dialog-5b7bce58.js.map +1 -0
  17. package/dist/assets/el-dialog-legacy.e6ef2c86.js +2 -0
  18. package/dist/assets/el-dropdown-item-0c6ddabc.css +1 -0
  19. package/dist/assets/el-dropdown-item-e0275106.js +2 -0
  20. package/dist/assets/el-dropdown-item-e0275106.js.map +1 -0
  21. package/dist/assets/el-dropdown-item-legacy.4888d114.js +2 -0
  22. package/dist/assets/el-form-item-3aad794a.css +1 -0
  23. package/dist/assets/el-form-item-c0658f70.js +2 -0
  24. package/dist/assets/el-form-item-c0658f70.js.map +1 -0
  25. package/dist/assets/el-form-item-legacy.a8e8784e.js +2 -0
  26. package/dist/assets/el-loading-c8798044.js +2 -0
  27. package/dist/assets/el-loading-c8798044.js.map +1 -0
  28. package/dist/assets/el-loading-d0f2d079.css +1 -0
  29. package/dist/assets/el-loading-legacy.534bd799.js +2 -0
  30. package/dist/assets/el-pagination-bf7c736d.css +1 -0
  31. package/dist/assets/el-pagination-dabcccbb.js +2 -0
  32. package/dist/assets/el-pagination-dabcccbb.js.map +1 -0
  33. package/dist/assets/el-pagination-legacy.7d2ae10d.js +2 -0
  34. package/dist/assets/el-progress-54b274cd.js +2 -0
  35. package/dist/assets/el-progress-54b274cd.js.map +1 -0
  36. package/dist/assets/el-progress-63aabe3a.css +1 -0
  37. package/dist/assets/el-progress-legacy.07ca6502.js +2 -0
  38. package/dist/assets/el-select-6be23320.css +1 -0
  39. package/dist/assets/el-select-f81a7377.js +2 -0
  40. package/dist/assets/el-select-f81a7377.js.map +1 -0
  41. package/dist/assets/el-select-legacy.94fad7fa.js +2 -0
  42. package/dist/assets/el-switch-9eba6fd0.js +2 -0
  43. package/dist/assets/el-switch-9eba6fd0.js.map +1 -0
  44. package/dist/assets/el-switch-aeab2c6b.css +1 -0
  45. package/dist/assets/el-switch-legacy.490534be.js +2 -0
  46. package/dist/assets/el-tab-pane-4a1bb4c7.css +1 -0
  47. package/dist/assets/el-tab-pane-89bdd69b.js +2 -0
  48. package/dist/assets/el-tab-pane-89bdd69b.js.map +1 -0
  49. package/dist/assets/el-tab-pane-legacy.cfdbc441.js +2 -0
  50. package/dist/assets/el-table-column-6716308a.js +21 -0
  51. package/dist/assets/el-table-column-6716308a.js.map +1 -0
  52. package/dist/assets/el-table-column-6c2089f9.css +1 -0
  53. package/dist/assets/el-table-column-legacy.49685e5a.js +24 -0
  54. package/dist/assets/index-01e33329.css +1 -0
  55. package/dist/assets/index-0b0f29ec.js +2 -0
  56. package/dist/assets/index-0b0f29ec.js.map +1 -0
  57. package/dist/assets/index-17c6005d.css +1 -0
  58. package/dist/assets/index-20019c57.js +2 -0
  59. package/dist/assets/index-20019c57.js.map +1 -0
  60. package/dist/assets/index-247f2c67.css +1 -0
  61. package/dist/assets/index-248e88e2.js +2 -0
  62. package/dist/assets/index-248e88e2.js.map +1 -0
  63. package/dist/assets/index-3091894a.css +1 -0
  64. package/dist/assets/index-37e15bc6.css +1 -0
  65. package/dist/assets/index-39637d43.js +2 -0
  66. package/dist/assets/index-39637d43.js.map +1 -0
  67. package/dist/assets/index-3f82ab7a.css +1 -0
  68. package/dist/assets/index-4c81cf78.css +1 -0
  69. package/dist/assets/index-5099f123.js +2 -0
  70. package/dist/assets/index-5099f123.js.map +1 -0
  71. package/dist/assets/index-57513f17.css +1 -0
  72. package/dist/assets/index-76f31e30.css +1 -0
  73. package/dist/assets/index-76ff9b9b.css +1 -0
  74. package/dist/assets/index-8557974a.js +2 -0
  75. package/dist/assets/index-8557974a.js.map +1 -0
  76. package/dist/assets/index-85fcd87a.css +1 -0
  77. package/dist/assets/index-867d07e4.js +2 -0
  78. package/dist/assets/index-867d07e4.js.map +1 -0
  79. package/dist/assets/index-8f353d3b.js +2 -0
  80. package/dist/assets/index-8f353d3b.js.map +1 -0
  81. package/dist/assets/index-8f7abc30.js +2 -0
  82. package/dist/assets/index-8f7abc30.js.map +1 -0
  83. package/dist/assets/index-8fbd06a5.js +2 -0
  84. package/dist/assets/index-8fbd06a5.js.map +1 -0
  85. package/dist/assets/index-93c733b3.css +1 -0
  86. package/dist/assets/index-98b55468.css +1 -0
  87. package/dist/assets/index-9e6bd406.js +2 -0
  88. package/dist/assets/index-9e6bd406.js.map +1 -0
  89. package/dist/assets/index-a880597c.css +1 -0
  90. package/dist/assets/index-acdbf3b6.js +2 -0
  91. package/dist/assets/index-acdbf3b6.js.map +1 -0
  92. package/dist/assets/index-b3e58b02.js +2 -0
  93. package/dist/assets/index-b3e58b02.js.map +1 -0
  94. package/dist/assets/index-c13133c5.js +2 -0
  95. package/dist/assets/index-c13133c5.js.map +1 -0
  96. package/dist/assets/index-c1d6836c.js +2 -0
  97. package/dist/assets/index-c1d6836c.js.map +1 -0
  98. package/dist/assets/index-d26aeed5.css +1 -0
  99. package/dist/assets/index-d98be3e4.js +19 -0
  100. package/dist/assets/index-d98be3e4.js.map +1 -0
  101. package/dist/assets/index-d9db6cc1.js +2 -0
  102. package/dist/assets/index-d9db6cc1.js.map +1 -0
  103. package/dist/assets/index-da51da36.css +1 -0
  104. package/dist/assets/index-e0ef7135.js +2 -0
  105. package/dist/assets/index-e0ef7135.js.map +1 -0
  106. package/dist/assets/index-e7d8a83e.css +1 -0
  107. package/dist/assets/index-ebf625c9.js +2 -0
  108. package/dist/assets/index-ebf625c9.js.map +1 -0
  109. package/dist/assets/index-eda7d85a.js +2 -0
  110. package/dist/assets/index-eda7d85a.js.map +1 -0
  111. package/dist/assets/index-fdc557f8.js +2 -0
  112. package/dist/assets/index-fdc557f8.js.map +1 -0
  113. package/dist/assets/index-legacy.0c570346.js +2 -0
  114. package/dist/assets/index-legacy.24edddf9.js +2 -0
  115. package/dist/assets/index-legacy.31681402.js +2 -0
  116. package/dist/assets/index-legacy.3e6b32cf.js +2 -0
  117. package/dist/assets/index-legacy.4edc099d.js +2 -0
  118. package/dist/assets/index-legacy.614df679.js +2 -0
  119. package/dist/assets/index-legacy.6420d0ab.js +2 -0
  120. package/dist/assets/index-legacy.679e5ce1.js +2 -0
  121. package/dist/assets/index-legacy.7b42e0cb.js +2 -0
  122. package/dist/assets/index-legacy.7bafa2e6.js +2 -0
  123. package/dist/assets/index-legacy.7ff3d773.js +2 -0
  124. package/dist/assets/index-legacy.84e0eca9.js +2 -0
  125. package/dist/assets/index-legacy.9ca64f8c.js +2 -0
  126. package/dist/assets/index-legacy.a4371211.js +2 -0
  127. package/dist/assets/index-legacy.acb8b137.js +23 -0
  128. package/dist/assets/index-legacy.bc3790f6.js +2 -0
  129. package/dist/assets/index-legacy.d0e21cb1.js +2 -0
  130. package/dist/assets/index-legacy.daf56c8f.js +2 -0
  131. package/dist/assets/index-legacy.e12feae0.js +2 -0
  132. package/dist/assets/index-legacy.e7f8790c.js +2 -0
  133. package/dist/assets/index-legacy.f84efe08.js +2 -0
  134. package/dist/assets/isEqual-82bb65ad.js +2 -0
  135. package/dist/assets/isEqual-82bb65ad.js.map +1 -0
  136. package/dist/assets/isEqual-legacy.dbaa2a6e.js +2 -0
  137. package/dist/assets/other-8d7ba6a0.js +2 -0
  138. package/dist/assets/other-8d7ba6a0.js.map +1 -0
  139. package/dist/assets/other-legacy.39078796.js +2 -0
  140. package/dist/assets/polyfills-legacy.99e38685.js +4 -0
  141. package/dist/assets/refresh-f2c4c532.js +2 -0
  142. package/dist/assets/refresh-f2c4c532.js.map +1 -0
  143. package/dist/assets/refresh-legacy.0ee83ca1.js +2 -0
  144. package/dist/assets/tip-3d272885.js +2 -0
  145. package/dist/assets/tip-3d272885.js.map +1 -0
  146. package/dist/assets/tip-9cb18ee8.css +1 -0
  147. package/dist/assets/tip-legacy.dee89e85.js +2 -0
  148. package/dist/assets/validator-d4ea1237.js +2 -0
  149. package/dist/assets/validator-d4ea1237.js.map +1 -0
  150. package/dist/assets/validator-legacy.ecd1e5dd.js +2 -0
  151. package/{index.html → dist/index.html} +8 -1
  152. package/package.json +30 -19
  153. package/.env +0 -6
  154. package/.env.production +0 -3
  155. package/.env.test +0 -4
  156. package/.eslintignore +0 -0
  157. package/.eslintrc.json +0 -57
  158. package/.github/workflows/main.yml +0 -61
  159. package/.prettierrc.js +0 -9
  160. package/auto-imports.d.ts +0 -6
  161. package/components.d.ts +0 -56
  162. package/docker/ep_backup/easypicker2.sql +0 -214
  163. package/docker/ep_backup/mongodb/easypicker2/action.bson +0 -0
  164. package/docker/ep_backup/mongodb/easypicker2/action.metadata.json +0 -1
  165. package/docker/ep_backup/mongodb/easypicker2/log.bson +0 -0
  166. package/docker/ep_backup/mongodb/easypicker2/log.metadata.json +0 -1
  167. package/docker/ep_backup/user-config.json +0 -176
  168. package/docs/.env +0 -1
  169. package/docs/.env.production +0 -2
  170. package/docs/.vitepress/config.ts +0 -204
  171. package/docs/.vitepress/theme/bg.png +0 -0
  172. package/docs/.vitepress/theme/index.scss +0 -41
  173. package/docs/.vitepress/theme/index.ts +0 -5
  174. package/docs/author.md +0 -24
  175. package/docs/auto-imports.d.ts +0 -6
  176. package/docs/components.d.ts +0 -17
  177. package/docs/deploy/design/api.md +0 -3
  178. package/docs/deploy/design/db.md +0 -3
  179. package/docs/deploy/design/index.md +0 -3
  180. package/docs/deploy/design/shell.md +0 -9
  181. package/docs/deploy/faq.md +0 -86
  182. package/docs/deploy/index.md +0 -9
  183. package/docs/deploy/local.md +0 -275
  184. package/docs/deploy/online-new.md +0 -610
  185. package/docs/deploy/online.md +0 -683
  186. package/docs/deploy/qiniu.md +0 -183
  187. package/docs/index.md +0 -40
  188. package/docs/introduction/about/code.md +0 -26
  189. package/docs/introduction/about/index.md +0 -33
  190. package/docs/introduction/feature/index.md +0 -3
  191. package/docs/plan/log.md +0 -346
  192. package/docs/plan/todo.md +0 -127
  193. package/docs/plan/wish.md +0 -29
  194. package/docs/praise/index.md +0 -45
  195. package/docs/public/robots.txt +0 -2
  196. package/docs/src/apis/ajax.ts +0 -66
  197. package/docs/src/apis/index.ts +0 -1
  198. package/docs/src/apis/modules/wish.ts +0 -20
  199. package/docs/src/components/Avatar.vue +0 -60
  200. package/docs/src/components/Home.vue +0 -85
  201. package/docs/src/components/Picture.vue +0 -13
  202. package/docs/src/components/Praise.vue +0 -52
  203. package/docs/src/components/WishBtn.vue +0 -98
  204. package/docs/src/components/WishPanel.vue +0 -170
  205. package/docs/src/components/callme/index.vue +0 -72
  206. package/docs/vite.config.ts +0 -42
  207. package/public/favicon.ico +0 -0
  208. package/public/logo.png +0 -0
  209. package/scripts/deploy/docs.mjs +0 -24
  210. package/scripts/deploy/prod.mjs +0 -24
  211. package/scripts/deploy/test.mjs +0 -26
  212. package/src/@types/ajax.d.ts +0 -5
  213. package/src/@types/api.d.ts +0 -305
  214. package/src/@types/lib.d.ts +0 -26
  215. package/src/@types/page.d.ts +0 -18
  216. package/src/App.vue +0 -36
  217. package/src/apis/ajax.ts +0 -72
  218. package/src/apis/index.ts +0 -20
  219. package/src/apis/modules/action.ts +0 -17
  220. package/src/apis/modules/category.ts +0 -20
  221. package/src/apis/modules/config.ts +0 -19
  222. package/src/apis/modules/file.ts +0 -150
  223. package/src/apis/modules/people.ts +0 -81
  224. package/src/apis/modules/public.ts +0 -49
  225. package/src/apis/modules/super/overview.ts +0 -56
  226. package/src/apis/modules/super/user.ts +0 -62
  227. package/src/apis/modules/task.ts +0 -67
  228. package/src/apis/modules/user.ts +0 -56
  229. package/src/apis/modules/wish.ts +0 -31
  230. package/src/assets/i/EasyPicker.png +0 -0
  231. package/src/assets/logo.png +0 -0
  232. package/src/assets/styles/app.css +0 -69
  233. package/src/components/HomeFooter/index.vue +0 -134
  234. package/src/components/HomeHeader/index.vue +0 -156
  235. package/src/components/InfosForm/index.vue +0 -73
  236. package/src/components/MessageList/index.vue +0 -155
  237. package/src/components/MessagePanel/index.vue +0 -46
  238. package/src/components/Praise/index.vue +0 -102
  239. package/src/components/QrCode.vue +0 -44
  240. package/src/components/linkDialog.vue +0 -104
  241. package/src/components/loginPanel.vue +0 -92
  242. package/src/constants/index.ts +0 -83
  243. package/src/env.d.ts +0 -8
  244. package/src/main.ts +0 -19
  245. package/src/pages/404/index.vue +0 -59
  246. package/src/pages/about/index.vue +0 -152
  247. package/src/pages/callme/index.vue +0 -155
  248. package/src/pages/dashboard/config/index.vue +0 -304
  249. package/src/pages/dashboard/files/index.vue +0 -1152
  250. package/src/pages/dashboard/index.vue +0 -335
  251. package/src/pages/dashboard/manage/config/index.vue +0 -97
  252. package/src/pages/dashboard/manage/index.vue +0 -105
  253. package/src/pages/dashboard/manage/overview/index.vue +0 -486
  254. package/src/pages/dashboard/manage/user/index.vue +0 -678
  255. package/src/pages/dashboard/manage/wish/index.vue +0 -257
  256. package/src/pages/dashboard/tasks/components/CategoryPanel.vue +0 -208
  257. package/src/pages/dashboard/tasks/components/CreateTask.vue +0 -93
  258. package/src/pages/dashboard/tasks/components/TaskInfo.vue +0 -129
  259. package/src/pages/dashboard/tasks/components/infoPanel/ddl.vue +0 -96
  260. package/src/pages/dashboard/tasks/components/infoPanel/file.vue +0 -175
  261. package/src/pages/dashboard/tasks/components/infoPanel/info.vue +0 -467
  262. package/src/pages/dashboard/tasks/components/infoPanel/people.vue +0 -566
  263. package/src/pages/dashboard/tasks/components/infoPanel/template.vue +0 -146
  264. package/src/pages/dashboard/tasks/components/infoPanel/tip.vue +0 -55
  265. package/src/pages/dashboard/tasks/components/infoPanel/tipInfo.vue +0 -196
  266. package/src/pages/dashboard/tasks/index.vue +0 -302
  267. package/src/pages/dashboard/tasks/public.ts +0 -32
  268. package/src/pages/disabled/index.vue +0 -47
  269. package/src/pages/feedback/index.vue +0 -5
  270. package/src/pages/home/index.vue +0 -72
  271. package/src/pages/login/index.vue +0 -270
  272. package/src/pages/register/index.vue +0 -211
  273. package/src/pages/reset/index.vue +0 -186
  274. package/src/pages/task/index.vue +0 -895
  275. package/src/pages/wish/index.vue +0 -152
  276. package/src/router/Interceptor/index.ts +0 -112
  277. package/src/router/index.ts +0 -13
  278. package/src/router/routes/index.ts +0 -197
  279. package/src/shims-vue.d.ts +0 -6
  280. package/src/store/index.ts +0 -17
  281. package/src/store/modules/category.ts +0 -44
  282. package/src/store/modules/public.ts +0 -27
  283. package/src/store/modules/task.ts +0 -55
  284. package/src/store/modules/user.ts +0 -57
  285. package/src/utils/elementUI.ts +0 -8
  286. package/src/utils/networkUtil.ts +0 -236
  287. package/src/utils/other.ts +0 -25
  288. package/src/utils/regExp.ts +0 -11
  289. package/src/utils/stringUtil.ts +0 -241
  290. package/tsconfig.json +0 -24
  291. package/vite.config.ts +0 -55
  292. /package/{docs/public → dist}/favicon.ico +0 -0
  293. /package/{docs/public → dist}/logo.png +0 -0
@@ -1,895 +0,0 @@
1
- <template>
2
- <div class="task-panel">
3
- <div class="pc-nav">
4
- <div class="nav">
5
- <!-- LOGO -->
6
- <div class="logo">
7
- <router-link to="/">
8
- <img
9
- style="height: 40px; width: 170px"
10
- src="https://img.cdn.sugarat.top/easypicker/EasyPicker.png"
11
- alt="logo"
12
- />
13
- </router-link>
14
- </div>
15
- <nav>
16
- <div
17
- class="nav-item"
18
- v-for="(n, idx) in pcNavs"
19
- :key="idx"
20
- @click="handleNav(idx)"
21
- >
22
- {{ n.title }}
23
- </div>
24
- </nav>
25
- </div>
26
- </div>
27
- <!-- 有效 -->
28
- <div
29
- v-loading="isLoadingData"
30
- element-loading-text="Loading..."
31
- class="panel tc"
32
- v-if="k"
33
- >
34
- <!-- 任务名 -->
35
- <h1 class="name">
36
- {{ taskInfo.name }}
37
- </h1>
38
- <!-- 提示信息 -->
39
- <!-- 时间截止了也不再展示 -->
40
- <template v-if="tipData.text && (ddlStr ? !isOver : true)">
41
- <el-divider>⚠️ 注意事项 ⚠️</el-divider>
42
- <Tip>
43
- <div class="tip-wrapper">
44
- <p v-for="(t, i) in tipData.text.split('\n')" :key="i">
45
- {{ t.replace(/\s/g, '&nbsp;') }}
46
- </p>
47
- </div>
48
- </Tip>
49
- </template>
50
- <template v-if="imageList.length && (ddlStr ? !isOver : true)">
51
- <el-image
52
- hide-on-click-modal
53
- v-for="(img, idx) in imageList"
54
- :key="img.uid"
55
- style="width: 100px; height: 100px; margin: 10px"
56
- :src="img.url"
57
- :zoom-rate="1.2"
58
- :preview-src-list="imageList.map((v) => v.preview)"
59
- :initial-index="idx"
60
- fit="contain"
61
- />
62
- </template>
63
- <!-- 截止时间字符串 -->
64
- <template v-if="ddlStr">
65
- <el-divider>截止时间</el-divider>
66
- <h2 class="ddl">
67
- {{ timeInfo }}
68
- </h2>
69
- <div v-if="isOver">
70
- <el-empty description="已经结束啦!"> </el-empty>
71
- </div>
72
- </template>
73
- <!-- 未设置ddl 或者 设置了还未结束 -->
74
- <div v-if="!ddlStr || !isOver">
75
- <el-divider>必要信息填写</el-divider>
76
- <div class="infos">
77
- <div v-show="taskMoreInfo.people">
78
- <Tip>“姓名”在参与名单里才能正常提交</Tip>
79
- </div>
80
- <div v-if="showValidForm">
81
- <div class="infos">
82
- <el-form
83
- ref="validModalRef"
84
- :rules="validModalRules"
85
- status-icon
86
- :model="validModal"
87
- :disabled="disableForm"
88
- label-position="top"
89
- >
90
- <el-form-item prop="peopleName" label="姓名">
91
- <el-input
92
- :maxlength="14"
93
- clearable
94
- show-word-limit
95
- placeholder="参与者填写"
96
- v-model="validModal.peopleName"
97
- ></el-input>
98
- </el-form-item>
99
- </el-form>
100
- </div>
101
- </div>
102
- <InfosForm :infos="infos" :disabled="disableForm"></InfosForm>
103
- </div>
104
- <el-upload
105
- style="max-width: 400px; margin: 0 auto"
106
- :drag="!isMobile"
107
- action=""
108
- ref="fileUpload"
109
- :on-change="handleChangeFile"
110
- :before-remove="handleRemoveFile"
111
- :on-exceed="handleExceed"
112
- :auto-upload="false"
113
- multiple
114
- :limit="limitUploadCount"
115
- v-model:file-list="fileList"
116
- >
117
- <el-button v-if="isMobile" type="primary">选择文件</el-button>
118
- <template v-else>
119
- <el-icon class="el-icon--upload">
120
- <upload-filled />
121
- </el-icon>
122
- <div class="el-upload__text">
123
- 将文件拖于此处 or <em>直接选择文件</em>
124
- </div>
125
- </template>
126
- <template #tip>
127
- <div class="p10" v-show="!!calculateMd5Count">
128
- <tip
129
- >还有
130
- {{ calculateMd5Count }}
131
- 个文件正在生成校验信息,请稍等(1G通常需要20s)</tip
132
- >
133
- </div>
134
- </template>
135
- </el-upload>
136
- <div class="p10">
137
- <el-button
138
- v-if="isWithdraw"
139
- size="default"
140
- @click="startWithdraw"
141
- type="warning"
142
- :disabled="!allowWithdraw || !!calculateMd5Count"
143
- >一键撤回</el-button
144
- >
145
- <el-button
146
- v-else
147
- size="default"
148
- @click="submitUpload"
149
- type="success"
150
- :disabled="!allowUpload || !!calculateMd5Count"
151
- >提交文件</el-button
152
- >
153
- <el-button @click="checkSubmitStatus" size="default"
154
- >查询提交情况</el-button
155
- >
156
- </div>
157
- <!-- 提示信息 -->
158
- <div class="p10 option-tips">
159
- <tip v-if="formatData.status && formatData.format.length"
160
- >限制格式为:
161
- <span style="color: red">{{
162
- formatData.format.join(', ')
163
- }}</span></tip
164
- >
165
- <tip v-if="formatData.size"
166
- >限制文件大小不超过:
167
- <span style="color: red">{{
168
- formatSize(formatData.size)
169
- }}</span></tip
170
- >
171
- <template v-if="isWithdraw">
172
- <tip
173
- >① 须保证选择的文件与提交时的文件一致<br />
174
- ② 填写表单信息一致 <br />
175
-
176
- 完全一模一样的文件的提交记录(内容md5+命名),将会一次性全部撤回</tip
177
- >
178
- </template>
179
- <template v-else>
180
- <tip
181
- >① 选择完文件,点击 ”提交文件“即可 <br />
182
- ② <strong>选择大文件后需要等待一会儿才展示处理</strong>
183
- <template v-if="taskMoreInfo.template"
184
- ><br />
185
-
186
- <strong>
187
- <el-button
188
- type="primary"
189
- text
190
- style="color: #85ce61"
191
- size="small"
192
- @click="downloadTemplate"
193
- >右下角可 “查看提交示例”
194
- </el-button>
195
- </strong></template
196
- >
197
- </tip>
198
- </template>
199
- </div>
200
- <div class="withdraw">
201
- <el-button
202
- type="primary"
203
- text
204
- style="color: #85ce61"
205
- v-if="taskMoreInfo.template"
206
- size="small"
207
- @click="downloadTemplate"
208
- >查看提交示例</el-button
209
- >
210
- <el-button
211
- v-if="isWithdraw"
212
- @click="isWithdraw = false"
213
- size="small"
214
- type="primary"
215
- text
216
- >正常提交</el-button
217
- >
218
- <el-button
219
- v-else
220
- size="small"
221
- @click="isWithdraw = true"
222
- type="primary"
223
- text
224
- >我要撤回</el-button
225
- >
226
- </div>
227
- </div>
228
- </div>
229
- <!-- 无效任务 -->
230
- <div class="panel tc" v-else>
231
- <h1 class="name">
232
- {{ taskInfo.name }}
233
- </h1>
234
- </div>
235
- <LinkDialog
236
- v-model:value="showLinkModel"
237
- title="示例文件下载链接"
238
- :link="templateLink"
239
- ></LinkDialog>
240
- <div style="padding-top: 20px">
241
- <home-footer type="task"></home-footer>
242
- </div>
243
- </div>
244
- </template>
245
- <script lang="ts" setup>
246
- import { ElMessage, ElMessageBox } from 'element-plus'
247
- import type { UploadUserFile, UploadInstance, FormInstance } from 'element-plus'
248
- import { computed, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
249
- import { useRoute, useRouter } from 'vue-router'
250
- import HomeFooter from '@components/HomeFooter/index.vue'
251
- import LinkDialog from '@components/linkDialog.vue'
252
- import { UploadFilled } from '@element-plus/icons-vue'
253
- import { useStore } from 'vuex'
254
- import {
255
- formatDate,
256
- formatSize,
257
- getFileMd5Hash,
258
- getFileSuffix,
259
- normalizeFileName,
260
- parseFileFormat,
261
- parseInfo
262
- } from '@/utils/stringUtil'
263
- import { downLoadByUrl, qiniuUpload } from '@/utils/networkUtil'
264
- import { FileApi, PeopleApi, PublicApi, TaskApi } from '@/apis'
265
- import Tip from '../dashboard/tasks/components/infoPanel/tip.vue'
266
- import InfosForm from '@/components/InfosForm/index.vue'
267
-
268
- const $store = useStore()
269
- const isMobile = computed(() => $store.getters['public/isMobile'])
270
- // 顶部导航
271
- const $router = useRouter()
272
- const $route = useRoute()
273
- const pcNavs = reactive([
274
- {
275
- title: '我也要收集',
276
- path: 'https://docs.ep.sugarat.top/'
277
- }
278
- ])
279
- const handleNav = (idx: number) => {
280
- if (pcNavs[idx].path.startsWith('http')) {
281
- window.location.href = pcNavs[idx].path
282
- return
283
- }
284
- $router.push({
285
- path: pcNavs[idx].path
286
- })
287
- }
288
-
289
- // 任务基本信息展示
290
- const taskInfo = reactive<TaskApiTypes.TaskInfo>({ name: '', category: '' })
291
- const taskMoreInfo = reactive<Partial<TaskApiTypes.TaskInfo>>({})
292
- const formatData = computed(() => parseFileFormat(taskMoreInfo.format))
293
- const k = ref('')
294
-
295
- // 用于展示截止日期
296
- const waitTime = ref(0)
297
- // 判断是否结束
298
- const isOver = computed(() => waitTime.value <= 0)
299
- const waitTimeStr = computed(() => {
300
- let seconds = ~~(waitTime.value / 1000)
301
- let hour = ~~(seconds / (60 * 60))
302
- const day = ~~(hour / 24)
303
- hour %= 24
304
- const minute = ~~((seconds % 3600) / 60)
305
- seconds %= 60
306
- return `剩余${day}天${hour}时${minute}分${seconds}秒`
307
- })
308
- const refreshWaitTime = (loop = true) => {
309
- if (taskMoreInfo?.ddl) {
310
- const date = new Date(taskMoreInfo.ddl)
311
- waitTime.value = date.getTime() - Date.now()
312
- } else {
313
- waitTime.value = 0
314
- }
315
- if (loop) {
316
- setTimeout(() => {
317
- refreshWaitTime()
318
- }, 1000)
319
- }
320
- }
321
- const ddlStr = computed(() => {
322
- if (taskMoreInfo?.ddl) {
323
- const date = new Date(taskMoreInfo.ddl)
324
- return formatDate(date)
325
- }
326
- return ''
327
- })
328
-
329
- // 必填信息
330
- const infos = reactive<InfoItem[]>([])
331
-
332
- // 文件上传部分
333
-
334
- // 文件上传
335
- const fileList = ref<(UploadUserFile & { md5: string; subscription: any })[]>(
336
- []
337
- )
338
- const fileUpload = ref<UploadInstance>()
339
- const disableForm = computed(
340
- () => fileList.value.filter((item) => item.status === 'uploading').length > 0
341
- )
342
- const handleRemoveFile: any = (file: any) => {
343
- if (file.status === 'uploading' || file.status === 'success') {
344
- return ElMessageBox.confirm(
345
- '不影响已经上传成功的,正在上传的将取消上传',
346
- '确定从列表移除文件吗?'
347
- )
348
- .then(() => {
349
- if (file.status === 'uploading') {
350
- ElMessage.info(`取消${file.name}的上传`)
351
- // 取消上传
352
- file.subscription.unsubscribe() // 取消上传
353
- }
354
- return true
355
- })
356
- .catch(() => false)
357
- }
358
- return true
359
- }
360
-
361
- // 校验表单填写
362
- const isWriteFinish = computed(() => infos.every((item) => item.value))
363
- // 提交文件
364
-
365
- // 身份核验表单
366
- const isSameFieldName = computed(() => infos.find((v) => v.text === '姓名'))
367
- const showValidForm = computed(
368
- () => taskMoreInfo.people && !isSameFieldName.value
369
- )
370
- const validModal = reactive({
371
- peopleName: ''
372
- })
373
-
374
- const validatePeopleName = (rule: any, value: any, callback: any) => {
375
- if (!value) {
376
- callback(new Error('请输入姓名'))
377
- ElMessage.error('请输入姓名')
378
- return
379
- }
380
- // 异步校验
381
- PeopleApi.checkPeopleIsExist(k.value, value).then((res) => {
382
- if (!res.data.exist) {
383
- ElMessage.error('你不在此次提交名单中,如有疑问请联系管理员')
384
- }
385
- callback(
386
- res.data.exist
387
- ? undefined
388
- : new Error('你不在此次提交名单中,如有疑问请联系管理员')
389
- )
390
- })
391
- }
392
-
393
- const validModalRef = ref<FormInstance>()
394
- const validModalRules = reactive({
395
- peopleName: [{ validator: validatePeopleName, trigger: 'blur' }]
396
- })
397
- const confirmPeopleName = () => {
398
- // 处理表单必填项含有姓名的情况
399
- if (isSameFieldName.value) {
400
- const value = infos.find((v) => v.text === '姓名')?.value
401
- validModal.peopleName = value || ''
402
- return new Promise((resolve) => {
403
- validatePeopleName(null, value, resolve)
404
- }).then((v) => !v)
405
- }
406
- return validModalRef.value.validate((isValid: boolean) => isValid)
407
- }
408
-
409
- const startUpload = () => {
410
- const uploadFiles = fileList.value
411
- for (const file of uploadFiles) {
412
- if (!file.md5) {
413
- ElMessage.info(
414
- `文件(${file.name})的唯一指纹还在计算中,再等待一会儿再点击上传`
415
- )
416
- setTimeout(() => {
417
- ElMessage.info('文件越大计算时间越长(1G通常需要20s)')
418
- }, 100)
419
- } else if (file.status === 'ready') {
420
- // 开始上传
421
- file.status = 'uploading'
422
- let { name } = file
423
- const originName = name
424
- // 如果开启了自动重命名,这里重命名一下
425
- if (taskMoreInfo.rewrite) {
426
- name =
427
- infos.map((v) => v.value).join(formatData.value.splitChar || '-') +
428
- getFileSuffix(name)
429
- }
430
- // 替换不合法的字符
431
- name = normalizeFileName(name)
432
- const key = `easypicker2/${k.value}/${file.md5}/${name}`
433
-
434
- FileApi.getUploadToken().then((res) => {
435
- qiniuUpload(res.data.token, file.raw, key, {
436
- success(data: any) {
437
- const { fsize } = data
438
- FileApi.addFile({
439
- originName,
440
- name,
441
- taskKey: k.value,
442
- taskName: taskInfo.name,
443
- size: fsize,
444
- hash: file.md5,
445
- info: JSON.stringify(infos),
446
- people: validModal.peopleName
447
- }).then(() => {
448
- file.status = 'success'
449
- ElMessage.success(`文件:${file.name}提交成功`)
450
- if (taskMoreInfo.people) {
451
- // 无感知更新一下
452
- PeopleApi.updatePeopleStatus(
453
- k.value,
454
- name,
455
- validModal.peopleName,
456
- file.md5
457
- )
458
- }
459
- })
460
- },
461
- process(per: number, data: any, subscription: any) {
462
- file.percentage = Math.floor(per)
463
- // 挂载取消上传的方法
464
- file.subscription = subscription
465
- }
466
- })
467
- })
468
- }
469
- }
470
- }
471
-
472
- const submitUpload = async () => {
473
- if (!isWriteFinish.value) {
474
- ElMessage.warning('请先完成必要信息的填写')
475
- return
476
- }
477
-
478
- if (taskMoreInfo.people) {
479
- const isValid = await confirmPeopleName()
480
- if (!isValid) {
481
- return
482
- }
483
- }
484
- startUpload()
485
- }
486
-
487
- // 是否允许上传
488
- const allowUpload = computed(() => {
489
- for (const file of fileList.value) {
490
- if (file.status === 'ready') {
491
- return true
492
- }
493
- }
494
- return false
495
- })
496
-
497
- // 是否允许撤回
498
- const allowWithdraw = computed(() => {
499
- for (const file of fileList.value) {
500
- if (['success', 'ready'].includes(file.status)) {
501
- return true
502
- }
503
- }
504
- return false
505
- })
506
-
507
- // 添加文件
508
- // 正在计算MD5值的文件个数
509
- const calculateMd5Count = ref(0)
510
- const handleChangeFile = (file: any) => {
511
- // 校验文件后缀名
512
- const { name } = file
513
- if (formatData.value.format.length && formatData.value.status) {
514
- const suffix = getFileSuffix(name)
515
- if (!formatData.value.format.find((v) => suffix.endsWith(v))) {
516
- ElMessage.error(`${name} 格式不符合要球`)
517
- fileUpload.value.handleRemove(file)
518
- return
519
- }
520
- }
521
-
522
- // 校验文件大小
523
- if (formatData.value.size && formatData.value.size < file.size) {
524
- ElMessage.error(`${name} 大小${formatSize(file.size)} 不符合要求`)
525
- fileUpload.value.handleRemove(file)
526
- return
527
- }
528
-
529
- calculateMd5Count.value += 1
530
- // 计算md5 hash
531
- getFileMd5Hash(file.raw).then((str) => {
532
- file.md5 = str
533
- calculateMd5Count.value -= 1
534
- })
535
- }
536
-
537
- const limitUploadCount = computed(() => formatData.value.limit || 10)
538
- const handleExceed = () => {
539
- ElMessage.warning(
540
- `一次提交最多只能选择${limitUploadCount.value}个文件,请移除已经上传成功的或刷新页面`
541
- )
542
- }
543
- const showLinkModel = ref(false)
544
- const templateLink = ref('')
545
- const runWithdraw = () => {
546
- const uploadFiles = fileList.value
547
- for (const file of uploadFiles) {
548
- if (!file.md5) {
549
- ElMessage.info(
550
- `文件(${file.name})的唯一指纹还在计算中,再等待一会儿再点击上传`
551
- )
552
- setTimeout(() => {
553
- ElMessage.info('文件越大计算时间越长(1G通常需要20s)')
554
- }, 100)
555
- } else if (!['fail', 'uploading'].includes(file.status)) {
556
- // 准备开始撤回
557
- let { name } = file
558
-
559
- // 如果开启了自动重命名,这里重命名一下
560
- if (taskMoreInfo.rewrite) {
561
- name =
562
- infos.map((v) => v.value).join(formatData.value.splitChar || '-') +
563
- getFileSuffix(name)
564
- }
565
-
566
- FileApi.withdrawFile({
567
- taskKey: k.value,
568
- taskName: taskInfo.name,
569
- filename: name,
570
- hash: file.md5,
571
- info: JSON.stringify(infos),
572
- peopleName: validModal.peopleName
573
- })
574
- .then(() => {
575
- ElMessage.success(`文件:${file.name}撤回成功`)
576
- file.name += ' - (已撤回 ✅ )'
577
- file.status = 'fail'
578
- })
579
- .catch(() => {
580
- ElMessage.error(`撤回失败: 没有文件:${file.name}对应提交记录`)
581
- })
582
- }
583
- }
584
- }
585
- const downloadTemplate = () => {
586
- FileApi.getTemplateUrl(taskMoreInfo.template, k.value)
587
- .then((res) => {
588
- showLinkModel.value = true
589
- const { link } = res.data
590
- templateLink.value = link
591
- downLoadByUrl(link, taskMoreInfo.template)
592
- })
593
- .catch(() => {
594
- ElMessage.warning('文件已从服务器上移除,请联系管理员重新上传')
595
- })
596
- }
597
-
598
- // 撤回相关逻辑
599
- const isWithdraw = ref(false)
600
- const startWithdraw = async () => {
601
- // 校验表单填写
602
- if (!isWriteFinish.value) {
603
- ElMessage.warning('请先完成必要信息的填写')
604
- return
605
- }
606
- if (taskMoreInfo.people) {
607
- const isValid = await confirmPeopleName()
608
- if (!isValid) {
609
- return
610
- }
611
- }
612
- runWithdraw()
613
- }
614
-
615
- // 查询提交情况
616
- const checkSubmitStatus = async () => {
617
- // 校验表单填写
618
- if (!isWriteFinish.value) {
619
- ElMessage.warning('请先完成必要信息的填写,需和提交时信息完全一致')
620
- return
621
- }
622
- // 卡控人员限制
623
- if (taskMoreInfo.people) {
624
- const isValid = await confirmPeopleName()
625
- if (!isValid) {
626
- return
627
- }
628
- }
629
- FileApi.checkSubmitStatus(k.value, infos, validModal.peopleName).then(
630
- (res) => {
631
- if (res.data.isSubmit) {
632
- ElMessage.success('已经提交过啦')
633
- } else {
634
- ElMessage.warning('还未提交过哟')
635
- }
636
- }
637
- )
638
- }
639
- const isLoadingData = ref(false)
640
- const readyRefresh = ref(false)
641
- const isEqualInfos = (a: InfoItem[] = [], b: InfoItem[] = []) => {
642
- if (a.length !== b.length) {
643
- return false
644
- }
645
- return a.every(
646
- (v, i) =>
647
- v.type === b[i].type &&
648
- v.text === b[i].text &&
649
- isEqualInfos(v.children, b[i].children)
650
- )
651
- }
652
- const refreshTaskMoreInfo = (hot = false) => {
653
- TaskApi.getTaskMoreInfo(k.value).then((res) => {
654
- Object.assign(taskMoreInfo, res.data)
655
- if (!isEqualInfos(infos, parseInfo(taskMoreInfo.info))) {
656
- infos.splice(0, infos.length)
657
- infos.push(...parseInfo(taskMoreInfo.info))
658
- if (hot) {
659
- ElMessage.success('表单信息有更新')
660
- }
661
- }
662
- refreshWaitTime(false)
663
- isLoadingData.value = false
664
- })
665
- }
666
- const handleBlur = () => {
667
- readyRefresh.value = true
668
- }
669
- const handleFocus = () => {
670
- if (readyRefresh.value && !disableForm.value) {
671
- readyRefresh.value = false
672
- refreshTaskMoreInfo(true)
673
- }
674
- }
675
-
676
- // 展示的时间提示文案
677
- const timeInfo = computed(() => {
678
- if (!isOver.value) {
679
- return ddlStr.value + waitTimeStr.value
680
- }
681
- return ddlStr.value
682
- })
683
-
684
- // tipImage
685
- const tipData = reactive<{
686
- text: string
687
- imgs: {
688
- uid: number
689
- name: string
690
- }[]
691
- }>({
692
- text: '',
693
- imgs: []
694
- })
695
- const imageList = ref<
696
- { name: string; uid: number; preview?: string; url: string }[]
697
- >([])
698
-
699
- watch(
700
- () => taskMoreInfo.tip,
701
- () => {
702
- // 初始化
703
- try {
704
- const parseData = JSON.parse(taskMoreInfo.tip)
705
- tipData.imgs = parseData.imgs
706
- tipData.text = parseData.text || ''
707
- imageList.value = tipData.imgs.map((v) => {
708
- return {
709
- ...v,
710
- url: 'https://img.cdn.sugarat.top/mdImg/MTY3NzkxMDI1NTU1Nw==20140524124237518.gif'
711
- }
712
- })
713
- if (imageList.value.length) {
714
- // 异步填充url
715
- PublicApi.getTipImageUrl(
716
- k.value,
717
- imageList.value.map((v) => ({
718
- uid: v.uid,
719
- name: v.name
720
- }))
721
- ).then((v) => {
722
- v.data.forEach((url, idx) => {
723
- imageList.value[idx].url = url.cover
724
- Object.assign(imageList.value[idx], {
725
- preview: url.preview
726
- })
727
- })
728
- })
729
- }
730
- } catch {
731
- tipData.text = ''
732
- tipData.imgs = []
733
- imageList.value = []
734
- }
735
- }
736
- )
737
- onMounted(() => {
738
- k.value = $route.params.key as string
739
- if (k.value) {
740
- isLoadingData.value = true
741
- TaskApi.getTaskInfo(k.value)
742
- .then((res) => {
743
- Object.assign(taskInfo, res.data)
744
- })
745
- .catch((err) => {
746
- if (err.code === 4001) {
747
- ElMessage.error('任务不存在')
748
- k.value = ''
749
- taskInfo.name = '任务不存在'
750
- }
751
- })
752
- refreshTaskMoreInfo()
753
- refreshWaitTime()
754
- }
755
- // 页面隐藏
756
- window.addEventListener('blur', handleBlur)
757
-
758
- // 页面展示
759
- window.addEventListener('focus', handleFocus)
760
- })
761
-
762
- onUnmounted(() => {
763
- // 页面隐藏
764
- window.removeEventListener('blur', handleBlur)
765
- // 页面展示
766
- window.removeEventListener('focus', handleFocus)
767
- })
768
- </script>
769
- <style scoped lang="scss">
770
- .task-panel :deep(ul.el-upload-list) {
771
- border: 1px dashed #d4d4d4;
772
- padding: 10px;
773
-
774
- &::before {
775
- content: '此处展示选择文件列表';
776
- font-size: 12px;
777
- position: relative;
778
- bottom: 4px;
779
- }
780
- }
781
-
782
- .task-panel :deep(.el-upload-list__item-name) {
783
- display: block;
784
- overflow: hidden;
785
- max-width: 290px;
786
- text-overflow: ellipsis;
787
- word-break: keep-all;
788
- }
789
-
790
- .task-panel :deep(.is-ready .el-icon--close) {
791
- display: block;
792
- color: black;
793
- }
794
-
795
- .task-panel {
796
- background-color: #f3f6f8;
797
- padding-bottom: 1rem;
798
- position: relative;
799
- }
800
-
801
- .pc-nav {
802
- background-color: #fff;
803
- display: flex;
804
- padding: 10px;
805
- justify-content: space-between;
806
- align-items: center;
807
-
808
- .exit {
809
- cursor: pointer;
810
- }
811
-
812
- .nav {
813
- display: flex;
814
-
815
- nav {
816
- display: flex;
817
- align-items: center;
818
-
819
- .nav-item {
820
- font-size: 1rem;
821
- color: #595959;
822
- padding: 10px;
823
- cursor: pointer;
824
-
825
- &.active {
826
- color: #409eff !important;
827
- font-weight: 600;
828
- }
829
- }
830
- }
831
-
832
- .exit {
833
- color: #595959;
834
- }
835
- }
836
-
837
- .logo {
838
- width: 180px;
839
- margin: 0 10px;
840
-
841
- img {
842
- height: 40px;
843
- }
844
- }
845
- }
846
-
847
- .panel {
848
- max-width: 1024px;
849
- padding: 1em;
850
- background-color: #fff;
851
- margin: 10px auto;
852
- box-sizing: border-box;
853
- box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
854
- border-radius: 4px;
855
-
856
- .name {
857
- text-align: center;
858
- }
859
-
860
- .ddl {
861
- margin-top: 10px;
862
- color: #919191;
863
- font-size: 14px;
864
- }
865
-
866
- .infos {
867
- max-width: 460px;
868
- margin: auto;
869
- overflow: hidden;
870
- :deep(div.el-form-item > label) {
871
- font-weight: bold;
872
- &::before {
873
- content: '* ';
874
- color: red;
875
- }
876
- }
877
- }
878
- }
879
-
880
- .withdraw {
881
- text-align: right;
882
- }
883
-
884
- .tip-wrapper {
885
- line-height: 20px;
886
- text-align: left;
887
- word-break: break-all;
888
- // max-height: 100px;
889
- overflow: hidden;
890
- padding: 0 20px;
891
- color: #e6a23c;
892
- max-width: 320px;
893
- font-size: 14px;
894
- }
895
- </style>