@sugarat/easypicker2-client 2.4.1

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 (145) hide show
  1. package/.env +6 -0
  2. package/.env.production +3 -0
  3. package/.env.test +4 -0
  4. package/.eslintignore +0 -0
  5. package/.eslintrc.json +57 -0
  6. package/.github/workflows/main.yml +61 -0
  7. package/.prettierrc.js +9 -0
  8. package/LICENSE +21 -0
  9. package/README.md +86 -0
  10. package/auto-imports.d.ts +6 -0
  11. package/components.d.ts +56 -0
  12. package/docker/ep_backup/easypicker2.sql +214 -0
  13. package/docker/ep_backup/mongodb/easypicker2/action.bson +0 -0
  14. package/docker/ep_backup/mongodb/easypicker2/action.metadata.json +1 -0
  15. package/docker/ep_backup/mongodb/easypicker2/log.bson +0 -0
  16. package/docker/ep_backup/mongodb/easypicker2/log.metadata.json +1 -0
  17. package/docker/ep_backup/user-config.json +176 -0
  18. package/docs/.env +1 -0
  19. package/docs/.env.production +2 -0
  20. package/docs/.vitepress/config.ts +204 -0
  21. package/docs/.vitepress/theme/bg.png +0 -0
  22. package/docs/.vitepress/theme/index.scss +41 -0
  23. package/docs/.vitepress/theme/index.ts +5 -0
  24. package/docs/author.md +24 -0
  25. package/docs/auto-imports.d.ts +6 -0
  26. package/docs/components.d.ts +17 -0
  27. package/docs/deploy/design/api.md +3 -0
  28. package/docs/deploy/design/db.md +3 -0
  29. package/docs/deploy/design/index.md +3 -0
  30. package/docs/deploy/design/shell.md +9 -0
  31. package/docs/deploy/faq.md +86 -0
  32. package/docs/deploy/index.md +9 -0
  33. package/docs/deploy/local.md +275 -0
  34. package/docs/deploy/online-new.md +610 -0
  35. package/docs/deploy/online.md +683 -0
  36. package/docs/deploy/qiniu.md +183 -0
  37. package/docs/index.md +40 -0
  38. package/docs/introduction/about/code.md +26 -0
  39. package/docs/introduction/about/index.md +33 -0
  40. package/docs/introduction/feature/index.md +3 -0
  41. package/docs/plan/log.md +333 -0
  42. package/docs/plan/todo.md +127 -0
  43. package/docs/plan/wish.md +29 -0
  44. package/docs/praise/index.md +45 -0
  45. package/docs/public/favicon.ico +0 -0
  46. package/docs/public/logo.png +0 -0
  47. package/docs/public/robots.txt +2 -0
  48. package/docs/src/apis/ajax.ts +66 -0
  49. package/docs/src/apis/index.ts +1 -0
  50. package/docs/src/apis/modules/wish.ts +20 -0
  51. package/docs/src/components/Avatar.vue +60 -0
  52. package/docs/src/components/Home.vue +85 -0
  53. package/docs/src/components/Picture.vue +13 -0
  54. package/docs/src/components/Praise.vue +52 -0
  55. package/docs/src/components/WishBtn.vue +98 -0
  56. package/docs/src/components/WishPanel.vue +170 -0
  57. package/docs/src/components/callme/index.vue +72 -0
  58. package/docs/vite.config.ts +42 -0
  59. package/index.html +127 -0
  60. package/package.json +52 -0
  61. package/public/favicon.ico +0 -0
  62. package/public/logo.png +0 -0
  63. package/scripts/deploy/docs.mjs +24 -0
  64. package/scripts/deploy/prod.mjs +24 -0
  65. package/scripts/deploy/test.mjs +26 -0
  66. package/src/@types/ajax.d.ts +5 -0
  67. package/src/@types/api.d.ts +305 -0
  68. package/src/@types/lib.d.ts +26 -0
  69. package/src/@types/page.d.ts +18 -0
  70. package/src/App.vue +36 -0
  71. package/src/apis/ajax.ts +70 -0
  72. package/src/apis/index.ts +20 -0
  73. package/src/apis/modules/action.ts +17 -0
  74. package/src/apis/modules/category.ts +20 -0
  75. package/src/apis/modules/config.ts +19 -0
  76. package/src/apis/modules/file.ts +150 -0
  77. package/src/apis/modules/people.ts +81 -0
  78. package/src/apis/modules/public.ts +49 -0
  79. package/src/apis/modules/super/overview.ts +56 -0
  80. package/src/apis/modules/super/user.ts +62 -0
  81. package/src/apis/modules/task.ts +67 -0
  82. package/src/apis/modules/user.ts +56 -0
  83. package/src/apis/modules/wish.ts +31 -0
  84. package/src/assets/i/EasyPicker.png +0 -0
  85. package/src/assets/logo.png +0 -0
  86. package/src/assets/styles/app.css +69 -0
  87. package/src/components/HomeFooter/index.vue +134 -0
  88. package/src/components/HomeHeader/index.vue +156 -0
  89. package/src/components/InfosForm/index.vue +73 -0
  90. package/src/components/MessageList/index.vue +155 -0
  91. package/src/components/MessagePanel/index.vue +42 -0
  92. package/src/components/Praise/index.vue +102 -0
  93. package/src/components/QrCode.vue +44 -0
  94. package/src/components/linkDialog.vue +104 -0
  95. package/src/components/loginPanel.vue +92 -0
  96. package/src/constants/index.ts +83 -0
  97. package/src/env.d.ts +8 -0
  98. package/src/main.ts +19 -0
  99. package/src/pages/404/index.vue +59 -0
  100. package/src/pages/about/index.vue +152 -0
  101. package/src/pages/callme/index.vue +155 -0
  102. package/src/pages/dashboard/config/index.vue +264 -0
  103. package/src/pages/dashboard/files/index.vue +1152 -0
  104. package/src/pages/dashboard/index.vue +335 -0
  105. package/src/pages/dashboard/manage/config/index.vue +97 -0
  106. package/src/pages/dashboard/manage/index.vue +105 -0
  107. package/src/pages/dashboard/manage/overview/index.vue +488 -0
  108. package/src/pages/dashboard/manage/user/index.vue +679 -0
  109. package/src/pages/dashboard/manage/wish/index.vue +257 -0
  110. package/src/pages/dashboard/tasks/components/CategoryPanel.vue +208 -0
  111. package/src/pages/dashboard/tasks/components/CreateTask.vue +93 -0
  112. package/src/pages/dashboard/tasks/components/TaskInfo.vue +129 -0
  113. package/src/pages/dashboard/tasks/components/infoPanel/ddl.vue +96 -0
  114. package/src/pages/dashboard/tasks/components/infoPanel/file.vue +175 -0
  115. package/src/pages/dashboard/tasks/components/infoPanel/info.vue +477 -0
  116. package/src/pages/dashboard/tasks/components/infoPanel/people.vue +567 -0
  117. package/src/pages/dashboard/tasks/components/infoPanel/template.vue +146 -0
  118. package/src/pages/dashboard/tasks/components/infoPanel/tip.vue +55 -0
  119. package/src/pages/dashboard/tasks/components/infoPanel/tipInfo.vue +196 -0
  120. package/src/pages/dashboard/tasks/index.vue +302 -0
  121. package/src/pages/dashboard/tasks/public.ts +32 -0
  122. package/src/pages/disabled/index.vue +47 -0
  123. package/src/pages/feedback/index.vue +5 -0
  124. package/src/pages/home/index.vue +72 -0
  125. package/src/pages/login/index.vue +270 -0
  126. package/src/pages/register/index.vue +211 -0
  127. package/src/pages/reset/index.vue +186 -0
  128. package/src/pages/task/index.vue +897 -0
  129. package/src/pages/wish/index.vue +152 -0
  130. package/src/router/Interceptor/index.ts +112 -0
  131. package/src/router/index.ts +13 -0
  132. package/src/router/routes/index.ts +197 -0
  133. package/src/shims-vue.d.ts +6 -0
  134. package/src/store/index.ts +17 -0
  135. package/src/store/modules/category.ts +44 -0
  136. package/src/store/modules/public.ts +27 -0
  137. package/src/store/modules/task.ts +55 -0
  138. package/src/store/modules/user.ts +57 -0
  139. package/src/utils/elementUI.ts +8 -0
  140. package/src/utils/networkUtil.ts +236 -0
  141. package/src/utils/other.ts +25 -0
  142. package/src/utils/regExp.ts +11 -0
  143. package/src/utils/stringUtil.ts +242 -0
  144. package/tsconfig.json +24 -0
  145. package/vite.config.ts +55 -0
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div class="tip tc">
3
+ <div>
4
+ <slot></slot>
5
+ </div>
6
+ <div v-if="imgs?.length" class="preview">
7
+ <el-image
8
+ hide-on-click-modal
9
+ class="img-container"
10
+ :src="imgs[0]"
11
+ :preview-src-list="imgs"
12
+ :initial-index="0"
13
+ fit="cover"
14
+ />
15
+ <el-icon class="icon">
16
+ <opportunity />
17
+ </el-icon>
18
+ </div>
19
+ </div>
20
+ </template>
21
+ <script setup lang="ts">
22
+ import { Opportunity } from '@element-plus/icons-vue'
23
+
24
+ defineProps<{
25
+ imgs?: string[]
26
+ }>()
27
+ </script>
28
+
29
+ <style scoped>
30
+ .tip {
31
+ color: #909399;
32
+ padding-bottom: 10px;
33
+ font-size: 12px;
34
+ display: flex;
35
+ justify-content: center;
36
+ left: 0;
37
+ top: 4px;
38
+ }
39
+ .preview {
40
+ position: relative;
41
+ }
42
+ .icon {
43
+ position: absolute;
44
+ pointer-events: none;
45
+ background-color: #fff;
46
+ left: 0;
47
+ top: 1px;
48
+ font-size: 14px;
49
+ color: #53a8ff;
50
+ }
51
+ .img-container {
52
+ width: 10px;
53
+ height: 10px;
54
+ }
55
+ </style>
@@ -0,0 +1,196 @@
1
+ <template>
2
+ <div class="tc ddl">
3
+ <tip
4
+ :imgs="[
5
+ 'https://img.cdn.sugarat.top/mdImg/MTY1MTQ5NjI2OTI0MQ==651496269241'
6
+ ]"
7
+ >设置注意事项,供用户提交时查看</tip
8
+ >
9
+ <tip>注意控制字数和换行,避免展示异常,建议内容不超过5行</tip>
10
+ <div class="tc flex fc fac">
11
+ <el-input
12
+ v-model="textValue"
13
+ :rows="5"
14
+ clearable
15
+ :max="500"
16
+ show-word-limit
17
+ type="textarea"
18
+ placeholder="请输入要展示的批注信息"
19
+ />
20
+ </div>
21
+ <div class="p10">
22
+ <el-button size="default" @click="updateTip" type="success"
23
+ >保存</el-button
24
+ >
25
+ <el-button size="default" @click="textValue = ''" type="danger"
26
+ >清空</el-button
27
+ >
28
+ </div>
29
+ <tip v-if="needSave"> 有变动记得保存 </tip>
30
+ <tip> 可以设置图片啦↓ 最多3张 </tip>
31
+ <el-upload
32
+ accept="image/*"
33
+ :limit="MaxImgCount"
34
+ v-model:file-list="imageList"
35
+ action=""
36
+ ref="imgUpload"
37
+ list-type="picture-card"
38
+ :on-change="handleChangeFile"
39
+ :on-exceed="handleExceedFile"
40
+ :on-preview="handlePictureCardPreview"
41
+ :on-remove="handleRemove"
42
+ :auto-upload="false"
43
+ >
44
+ <el-icon><Plus /></el-icon>
45
+ </el-upload>
46
+ <ElImageViewer
47
+ hide-on-click-modal
48
+ :initial-index="previewIdx"
49
+ :url-list="previewList"
50
+ @close="imageViewerVisible = false"
51
+ teleported
52
+ v-if="imageViewerVisible"
53
+ />
54
+ </div>
55
+ </template>
56
+ <script lang="ts" setup>
57
+ import { ref, watch, computed, reactive } from 'vue'
58
+ import { Plus } from '@element-plus/icons-vue'
59
+ import { ElMessage, UploadProps, UploadUserFile } from 'element-plus'
60
+ import { updateTaskInfo } from '../../public'
61
+ import Tip from './tip.vue'
62
+ import { FileApi, PublicApi, TaskApi } from '@/apis'
63
+ import { qiniuUpload } from '@/utils/networkUtil'
64
+ import { getTipImageKey } from '@/utils/stringUtil'
65
+
66
+ const props = defineProps({
67
+ tip: {
68
+ type: String,
69
+ default: '',
70
+ required: false
71
+ },
72
+ k: {
73
+ type: String,
74
+ default: ''
75
+ }
76
+ })
77
+ const textValue = ref('')
78
+
79
+ const tipData = reactive<{
80
+ text: string
81
+ imgs: {
82
+ uid: number
83
+ name: string
84
+ }[]
85
+ }>({
86
+ text: '',
87
+ imgs: []
88
+ })
89
+ const MaxImgCount = ref(3)
90
+ const imageList = ref<UploadUserFile[]>([])
91
+ const previewList = computed(() => {
92
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
93
+ // @ts-ignore
94
+ return imageList.value.map((v) => v!.preview || v.url)
95
+ })
96
+ const previewIdx = ref(0)
97
+
98
+ watch(
99
+ () => props.tip,
100
+ () => {
101
+ // 初始化
102
+ try {
103
+ const parseData = JSON.parse(props.tip)
104
+ tipData.imgs = parseData.imgs
105
+ tipData.text = parseData.text || ''
106
+ imageList.value = tipData.imgs.map((v) => {
107
+ return {
108
+ ...v,
109
+ url: 'https://img.cdn.sugarat.top/mdImg/MTY3NzkxMDI1NTU1Nw==20140524124237518.gif'
110
+ }
111
+ })
112
+ if (imageList.value.length) {
113
+ // 异步填充url
114
+ PublicApi.getTipImageUrl(
115
+ props.k,
116
+ imageList.value.map((v) => ({
117
+ uid: v.uid,
118
+ name: v.name
119
+ }))
120
+ ).then((v) => {
121
+ v.data.forEach((url, idx) => {
122
+ imageList.value[idx].url = url.cover
123
+ Object.assign(imageList.value[idx], {
124
+ preview: url.preview
125
+ })
126
+ })
127
+ })
128
+ }
129
+ } catch {
130
+ tipData.text = props.tip || ''
131
+ tipData.imgs = []
132
+ imageList.value = []
133
+ }
134
+
135
+ // 外部变动
136
+ if (tipData.text) {
137
+ textValue.value = tipData.text
138
+ } else {
139
+ textValue.value = ''
140
+ }
141
+ },
142
+ {
143
+ immediate: true
144
+ }
145
+ )
146
+ const needSave = computed(() => tipData.text !== textValue.value)
147
+
148
+ // 更新批注信息
149
+ const updateTip = (notify = true) => {
150
+ if (tipData.text !== textValue.value) {
151
+ tipData.text = textValue.value
152
+ }
153
+ updateTaskInfo(props.k, { tip: JSON.stringify(tipData) }, notify)
154
+ }
155
+
156
+ const imageViewerVisible = ref(false)
157
+ const handleChangeFile = (file: UploadUserFile) => {
158
+ if (!props.k) {
159
+ return
160
+ }
161
+ const { name, uid } = file
162
+ const key = getTipImageKey(props.k, name, uid)
163
+ if (file.status === 'ready') {
164
+ file.status = 'success'
165
+ // qiniu上传
166
+ FileApi.getUploadToken().then((res) => {
167
+ qiniuUpload(res.data.token, file.raw, key, {
168
+ success() {
169
+ tipData.imgs.push({
170
+ uid,
171
+ name
172
+ })
173
+ updateTip()
174
+ }
175
+ })
176
+ })
177
+ }
178
+ }
179
+ const handleRemove: UploadProps['onRemove'] = (file) => {
180
+ const { uid, name } = file
181
+ const idx = tipData.imgs.findIndex((v) => v.uid === uid)
182
+ tipData.imgs.splice(idx, 1)
183
+ updateTip()
184
+ TaskApi.delTipImage(props.k, uid, name)
185
+ }
186
+
187
+ const handlePictureCardPreview = (file) => {
188
+ imageViewerVisible.value = true
189
+ const idx = imageList.value.findIndex((v) => v.uid === file.uid)
190
+ previewIdx.value = idx
191
+ }
192
+ // 超出选择的文件个数
193
+ const handleExceedFile = () => {
194
+ ElMessage.error(`只能选择${MaxImgCount.value}个图片,可删除后重新选择`)
195
+ }
196
+ </script>
@@ -0,0 +1,302 @@
1
+ <template>
2
+ <div class="tasks">
3
+ <!-- 分类管理 -->
4
+ <div class="categorys-area">
5
+ <CategoryPanel v-model:category="selectCategory"></CategoryPanel>
6
+ </div>
7
+
8
+ <!-- 任务管理 -->
9
+ <div class="panel task-panel">
10
+ <!-- 创建任务 -->
11
+ <create-task :activeCategoryKey="selectCategory"></create-task>
12
+
13
+ <!-- 任务列表 -->
14
+ <div class="task-list">
15
+ <TaskInfo
16
+ @edit="editBaseInfo"
17
+ @delete="deleteTask"
18
+ @share="shareTask"
19
+ @more="editMore"
20
+ v-for="item in filterTasks"
21
+ :key="item.key"
22
+ :item="item"
23
+ ></TaskInfo>
24
+ <el-empty
25
+ v-if="filterTasks.length === 0"
26
+ description="此分类下没有任务哟,快去创建吧"
27
+ ></el-empty>
28
+ </div>
29
+ </div>
30
+
31
+ <!-- 任务基本信息维护弹窗 -->
32
+ <el-dialog
33
+ draggable
34
+ :fullscreen="isMobile"
35
+ title="基本信息修改"
36
+ v-model="showBaseInfoDialog"
37
+ >
38
+ <el-form :model="taskBaseInfo">
39
+ <el-form-item label="任务名称" label-width="100px">
40
+ <el-input v-model="taskBaseInfo.name" autocomplete="off"></el-input>
41
+ </el-form-item>
42
+ <el-form-item label="新的分类" label-width="100px">
43
+ <el-select v-model="taskBaseInfo.category" placeholder="请选择新分类">
44
+ <el-option label="默认" value="default"></el-option>
45
+ <el-option
46
+ v-for="c in categorys"
47
+ :key="c.k"
48
+ :label="c.name"
49
+ :value="c.k"
50
+ ></el-option>
51
+ </el-select>
52
+ </el-form-item>
53
+ </el-form>
54
+ <template #footer>
55
+ <span class="dialog-footer">
56
+ <el-button @click="showBaseInfoDialog = false">取 消</el-button>
57
+ <el-button type="primary" @click="handleSaveEditInfo"
58
+ >确 定</el-button
59
+ >
60
+ </span>
61
+ </template>
62
+ </el-dialog>
63
+
64
+ <!-- 分享链接弹窗(二维码/链接/短链) -->
65
+ <LinkDialog
66
+ v-model:value="showLinkModal"
67
+ :download="false"
68
+ title="收取链接"
69
+ :link="shareTaskLink"
70
+ >
71
+ </LinkDialog>
72
+ <!-- 附加属性编辑弹窗 -->
73
+ <el-dialog
74
+ :fullscreen="isMobile"
75
+ title="更多设置"
76
+ v-model="showTaskInfoPanel"
77
+ center
78
+ >
79
+ <div>
80
+ <h3 class="tc" style="font-size: 14px; color: #9e9e9e">
81
+ 任务名:<strong style="color: #000000">{{ activeTask.name }}</strong
82
+ >,
83
+ <el-button type="primary" text @click="openTaskPage"
84
+ >去查看效果</el-button
85
+ >
86
+ </h3>
87
+ <el-tabs v-model="activeInfo">
88
+ <el-tab-pane label="截止日期" name="ddl">
89
+ <DDlPanel :ddl="taskInfo.ddl" :k="activeTask.key" />
90
+ </el-tab-pane>
91
+ <el-tab-pane label="批注信息" name="tip">
92
+ <TipInfoPanel
93
+ :rewrite="taskInfo.rewrite"
94
+ :tip="taskInfo.tip"
95
+ :k="activeTask.key"
96
+ />
97
+ </el-tab-pane>
98
+ <el-tab-pane label="限制人员" name="people">
99
+ <PeoplePanel
100
+ :name="activeTask.name"
101
+ :value="taskInfo.people"
102
+ :k="activeTask.key"
103
+ />
104
+ </el-tab-pane>
105
+ <el-tab-pane label="必填信息" name="info">
106
+ <InfoPanel
107
+ :rewrite="taskInfo.rewrite"
108
+ :info="taskInfo.info"
109
+ :k="activeTask.key"
110
+ :format="taskInfo.format"
111
+ />
112
+ </el-tab-pane>
113
+ <el-tab-pane label="模板文件" name="template">
114
+ <TemplatePanel :value="taskInfo.template" :k="activeTask.key" />
115
+ </el-tab-pane>
116
+ <el-tab-pane label="文件属性" name="attr">
117
+ <FileInfoPanel :format="taskInfo.format" :k="activeTask.key" />
118
+ </el-tab-pane>
119
+ </el-tabs>
120
+ </div>
121
+ </el-dialog>
122
+ </div>
123
+ </template>
124
+ <script lang="ts" setup>
125
+ import { ElMessage, ElMessageBox } from 'element-plus'
126
+ import { computed, onMounted, reactive, ref, watchEffect } from 'vue'
127
+ import { useStore } from 'vuex'
128
+ import LinkDialog from '@components/linkDialog.vue'
129
+ import { TaskApi } from '@/apis'
130
+ import { copyRes } from '@/utils/stringUtil'
131
+ import CategoryPanel from './components/CategoryPanel.vue'
132
+ import CreateTask from './components/CreateTask.vue'
133
+ import TaskInfo from './components/TaskInfo.vue'
134
+ import DDlPanel from './components/infoPanel/ddl.vue'
135
+ import PeoplePanel from './components/infoPanel/people.vue'
136
+ import TemplatePanel from './components/infoPanel/template.vue'
137
+ import InfoPanel from './components/infoPanel/info.vue'
138
+ import TipInfoPanel from './components/infoPanel/tipInfo.vue'
139
+ import FileInfoPanel from './components/infoPanel/file.vue'
140
+
141
+ const $store = useStore()
142
+ const isMobile = computed(() => $store.getters['public/isMobile'])
143
+ // 分类相关
144
+ const categorys = computed(() => $store.state.category.categoryList)
145
+
146
+ // 任务相关
147
+ const selectCategory = ref('default')
148
+ const tasks = computed<TaskApiTypes.TaskItem[]>(
149
+ () => $store.state.task.taskList
150
+ )
151
+ const filterTasks = computed(() => {
152
+ const t = tasks.value.filter((v) => v.category === selectCategory.value)
153
+ return t
154
+ })
155
+
156
+ // 删除任务
157
+ const deleteTask = (k: string, isTrash = false) => {
158
+ if (!k) return
159
+ ElMessageBox.confirm(
160
+ '确认删除此任务吗?',
161
+ isTrash ? '!!回收站的删除后无法再恢复' : '数据无价,请谨慎操作',
162
+ {
163
+ confirmButtonText: '确定',
164
+ cancelButtonText: '取消',
165
+ type: isTrash ? 'error' : 'info'
166
+ }
167
+ )
168
+ .then(() => {
169
+ $store.dispatch('task/deleteTask', k).then(() => {
170
+ ElMessage.success('删除成功')
171
+ })
172
+ })
173
+ .catch(() => {
174
+ ElMessage.info('取消删除')
175
+ })
176
+ }
177
+
178
+ // 基本信息编辑
179
+ const showBaseInfoDialog = ref(false)
180
+ const taskBaseInfo = reactive({ name: '', category: '', key: '' })
181
+ const editBaseInfo = (task: any) => {
182
+ taskBaseInfo.name = task.name
183
+ taskBaseInfo.category = task.category
184
+ taskBaseInfo.key = task.key
185
+ showBaseInfoDialog.value = true
186
+ }
187
+ const handleSaveEditInfo = () => {
188
+ showBaseInfoDialog.value = false
189
+ if (!taskBaseInfo.name.trim()) {
190
+ ElMessage.warning('不能为空')
191
+ return
192
+ }
193
+ $store.dispatch('task/updateTask', taskBaseInfo).then(() => {
194
+ ElMessage.success('更新成功')
195
+ })
196
+ }
197
+
198
+ // 生成分享链接
199
+ const shareTaskLink = ref('')
200
+ const showLinkModal = ref(false)
201
+ const shareTask = (k: string) => {
202
+ shareTaskLink.value = 'default'
203
+ const { origin } = window.location
204
+ shareTaskLink.value = `${origin}/task/${k}`
205
+ copyRes(shareTaskLink.value, '收集链接已自动复制到粘贴板')
206
+ showLinkModal.value = true
207
+ }
208
+
209
+ // 附加属性编辑
210
+ const taskInfo = reactive<TaskApiTypes.TaskInfo>({})
211
+ const showTaskInfoPanel = ref(false)
212
+ const activeInfo = ref('info')
213
+ const activeTask: TaskApiTypes.TaskItem = reactive({
214
+ category: '',
215
+ key: '',
216
+ name: '',
217
+ recentLog: []
218
+ })
219
+ const editMore = (item: any) => {
220
+ Object.assign(activeTask, item)
221
+ TaskApi.getTaskMoreInfo(item.key).then((res) => {
222
+ // 先初始化,再赋值
223
+ taskInfo.info = '[]'
224
+ taskInfo.ddl = ''
225
+ taskInfo.tip = ''
226
+ taskInfo.format = ''
227
+ setTimeout(() => {
228
+ Object.assign(taskInfo, res.data)
229
+ showTaskInfoPanel.value = true
230
+ })
231
+ })
232
+ }
233
+
234
+ // TODO: 有需要再优化,目前像bug
235
+ // 用于选择默认展示项目
236
+ // const taskCount = (c: string) => {
237
+ // const count = tasks.value.filter((t: any) => t.category === c).length
238
+ // return count
239
+ // }
240
+
241
+ // 选中一个有任务数据的分类
242
+ // watchEffect(() => {
243
+ // if (taskCount('default') > 0) {
244
+ // return
245
+ // }
246
+ // if (categorys.value.length > 0) {
247
+ // for (const c of categorys.value) {
248
+ // if (taskCount(c.k) > 0) {
249
+ // selectCategory.value = c.k
250
+ // break
251
+ // }
252
+ // }
253
+ // }
254
+ // })
255
+
256
+ onMounted(() => {
257
+ $store.dispatch('category/getCategory')
258
+ $store.dispatch('task/getTask')
259
+ })
260
+
261
+ const openTaskPage = () => {
262
+ window.open(`/task/${activeTask.key}`)
263
+ }
264
+ </script>
265
+ <style scoped lang="scss">
266
+ .tasks {
267
+ max-width: 1024px;
268
+ margin: 0 auto;
269
+ padding-bottom: 2em;
270
+ }
271
+
272
+ .tasks :deep(.el-dialog__body) {
273
+ padding-top: 10px;
274
+ }
275
+
276
+ .panel {
277
+ padding: 1em;
278
+ background-color: #fff;
279
+ margin: 10px auto;
280
+ box-sizing: border-box;
281
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
282
+ border-radius: 4px;
283
+ }
284
+
285
+ .task-list {
286
+ display: flex;
287
+ flex-wrap: wrap;
288
+ justify-content: space-around;
289
+ }
290
+
291
+ @media screen and (max-width: 700px) {
292
+ .categorys-area {
293
+ margin-top: 20px;
294
+ }
295
+ :deep(.el-tabs__nav-scroll) {
296
+ overflow-x: scroll;
297
+ &::-webkit-scrollbar {
298
+ display: none; /* Chrome Safari */
299
+ }
300
+ }
301
+ }
302
+ </style>
@@ -0,0 +1,32 @@
1
+ import { ElMessage } from 'element-plus'
2
+ import { TaskApi } from '@/apis'
3
+ import { debounce } from '@/utils/other'
4
+
5
+ export const updateTaskInfo: (
6
+ key: string,
7
+ options: TaskApiTypes.TaskInfo,
8
+ successInfo?: boolean
9
+ ) => void = debounce(
10
+ (key, options, successInfo = true) => {
11
+ if (key) {
12
+ TaskApi.updateTaskMoreInfo(key, options)
13
+ .then(() => {
14
+ if (successInfo) {
15
+ ElMessage.success({
16
+ message: '设置成功',
17
+ zIndex: 4000,
18
+ duration: 1000
19
+ })
20
+ }
21
+ })
22
+ .catch(() => {
23
+ ElMessage.error({
24
+ message: '设置失败',
25
+ zIndex: 4000
26
+ })
27
+ })
28
+ }
29
+ },
30
+ 1000,
31
+ true
32
+ )
@@ -0,0 +1,47 @@
1
+ <template>
2
+ <div class="not-found">
3
+ <h1>EasyPicker | 轻取</h1>
4
+ <h2>{{ $route.query.title }}:已被网站管理员禁用</h2>
5
+ <h3><a @click="handleToHome">查看应用介绍</a></h3>
6
+ </div>
7
+ </template>
8
+ <script lang="ts" setup>
9
+ import { useRoute } from 'vue-router'
10
+
11
+ const $route = useRoute()
12
+ const handleToHome = () => {
13
+ window.location.href = 'https://docs.ep.sugarat.top/'
14
+ }
15
+ </script>
16
+ <style lang="scss" scoped>
17
+ .not-found {
18
+ font-family: 'Avenir', Helvetica, Arial, sans-serif;
19
+ background-image: linear-gradient(to top, #30cfd0 0%, #330867 100%);
20
+ min-height: 100vh;
21
+ }
22
+ h1,
23
+ h2,
24
+ h3,
25
+ a {
26
+ color: aliceblue;
27
+ text-align: center;
28
+ font-weight: lighter;
29
+ }
30
+ a {
31
+ margin-left: 10px;
32
+ border-bottom: 2px solid aliceblue;
33
+ cursor: pointer;
34
+ }
35
+ h1 {
36
+ font-size: 48px;
37
+ padding-top: 10%;
38
+ }
39
+ h2 {
40
+ font-size: 30px;
41
+ padding-top: 2vh;
42
+ }
43
+ h3 {
44
+ font-size: 28px;
45
+ padding-top: 1vh;
46
+ }
47
+ </style>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <div>
3
+ <h1>反馈页</h1>
4
+ </div>
5
+ </template>