adtec-core-package 0.1.8 → 0.2.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.
package/README.en.md ADDED
@@ -0,0 +1,36 @@
1
+ # ADTEC前端核心包
2
+
3
+ #### Description
4
+ {**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
5
+
6
+ #### Software Architecture
7
+ Software architecture description
8
+
9
+ #### Installation
10
+
11
+ 1. xxxx
12
+ 2. xxxx
13
+ 3. xxxx
14
+
15
+ #### Instructions
16
+
17
+ 1. xxxx
18
+ 2. xxxx
19
+ 3. xxxx
20
+
21
+ #### Contribution
22
+
23
+ 1. Fork the repository
24
+ 2. Create Feat_xxx branch
25
+ 3. Commit your code
26
+ 4. Create Pull Request
27
+
28
+
29
+ #### Gitee Feature
30
+
31
+ 1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
32
+ 2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
33
+ 3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
34
+ 4. The most valuable open source project [GVP](https://gitee.com/gvp)
35
+ 5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
36
+ 6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adtec-core-package",
3
- "version": "0.1.8",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -13,7 +13,10 @@
13
13
  "format": "prettier --write src/"
14
14
  },
15
15
  "dependencies": {
16
+ "@onlyoffice/document-editor-vue": "1.4.0",
16
17
  "@element-plus/icons-vue": "^2.3.1",
18
+ "pinia-plugin-store": "^2.2.9",
19
+ "crypto-js": "^4.2.0",
17
20
  "axios": "^1.7.7",
18
21
  "element-plus": "^2.8.7",
19
22
  "pinia": "^2.3.0",
@@ -22,11 +25,14 @@
22
25
  "vue": "^3.5.13",
23
26
  "vue-focus-lock": "^3.0.0",
24
27
  "vue-router": "^4.5.0",
25
- "uuid": "^11.0.3"
28
+ "uuid": "^11.0.3",
29
+ "socket.io-client": "^2.3.1",
30
+ "vue-img-viewr": "2.0.11"
26
31
  },
27
32
  "devDependencies": {
28
33
  "@tsconfig/node22": "^22.0.0",
29
34
  "@types/node": "^22.10.2",
35
+ "@types/crypto-js": "^4.2.2",
30
36
  "@vitejs/plugin-vue": "^5.2.1",
31
37
  "@vitejs/plugin-vue-jsx": "^4.1.1",
32
38
  "@vue/eslint-config-prettier": "^10.1.0",
@@ -0,0 +1,18 @@
1
+ import request from '../utils/request'
2
+ import type { ISysUploadFiles } from '../interface/ISysUploadFiles.ts'
3
+
4
+ /**
5
+ * Create by丁盼
6
+ * 说明: DocumentApi
7
+ * 创建时间: 2025/1/2 11:05
8
+ * 修改时间: 2025/1/2 11:05
9
+ */
10
+ const basePath = '/api/doc/'
11
+ export default {
12
+ getUpLoadFilesVoById(id: string): Promise<ISysUploadFiles> {
13
+ return request.get(basePath + 'getUpLoadFilesVoById/' + id)
14
+ },
15
+ delSysUploadFile(id: string) {
16
+ return request.get(basePath + 'delSysUploadFile/' + id)
17
+ }
18
+ }
@@ -0,0 +1,12 @@
1
+ import request from '../utils/request'
2
+ export default {
3
+ /**
4
+ * 获取文件访问路径
5
+ * @param id
6
+ */
7
+ getFileAccessAddress(id: string): Promise<{
8
+ url: string
9
+ }> {
10
+ return request.get('/api/doc/getFileAccessAddress', { id })
11
+ },
12
+ }
@@ -0,0 +1,279 @@
1
+ <!--创建人 丁盼-->
2
+ <!--说明: 文档上传组件-->
3
+ <!--创建时间: 2024/12/2 下午1:59-->
4
+ <!--修改时间: 2024/12/2 下午1:59-->
5
+ <template>
6
+ <el-flex v-if="!isEdlt">
7
+ <el-flex
8
+ v-for="item of uploadFilesList"
9
+ :key="item.id"
10
+ class="file-class"
11
+ @click="fileView(item.id)"
12
+ :width="itemWidth"
13
+ >
14
+ <el-flex align="center" justify="flex-start">
15
+ <el-tooltip class="box-item" :content="item.name" placement="top">
16
+ <el-text truncated style="cursor: pointer"
17
+ ><el-icons :model-value="getIcon(item.name)" style="margin-right: 5px"></el-icons
18
+ >{{ item.name }}</el-text
19
+ >
20
+ </el-tooltip>
21
+ </el-flex>
22
+ </el-flex>
23
+ </el-flex>
24
+ <el-upload
25
+ v-else
26
+ ref="ref_upload"
27
+ :file-list="uploadFilesList"
28
+ @success="success"
29
+ @remove="remove"
30
+ @preview="preview"
31
+ @error="error"
32
+ @exceed="exceed"
33
+ :before-upload="beforeUpload"
34
+ drag
35
+ :accept="getAccept"
36
+ :action="'/api/doc/uploadFile/' + business + '/' + businessId + '/' + association"
37
+ multiple
38
+ :limit="limit"
39
+ :headers="uploadHeaders"
40
+ >
41
+ <el-icon class="el-icon--upload"><upload-filled /></el-icon>
42
+ <div class="el-upload__text">拖动文件或<em>点击上传</em></div>
43
+ <div class="el-upload__tip">最大上传文件大小{{ size }}MB</div>
44
+ <template #file="{ file }">
45
+ <el-flex
46
+ class="file-class"
47
+ @mousemove="mousemove(file.name)"
48
+ @mouseout="mouseout"
49
+ @click="preview(file)"
50
+ height="20px"
51
+ :width="itemWidth"
52
+ >
53
+ <el-flex align="center" justify="flex-start">
54
+ <el-tooltip class="box-item" :content="file.name" placement="top">
55
+ <el-text truncated style="cursor: pointer"
56
+ ><el-icons :model-value="getIcon(file.name)" style="margin-right: 5px"></el-icons
57
+ >{{ file.name }}</el-text
58
+ >
59
+ </el-tooltip>
60
+ </el-flex>
61
+ <el-flex align="center" justify="flex-end" width="50px">
62
+ <el-text v-if="!file?.businessId && file.percentage !== 100"
63
+ >{{ file.percentage }}%</el-text
64
+ >
65
+ <el-icons
66
+ v-if="file?.businessId || file.percentage === 100"
67
+ @click.prevent.stop="fileClick(file)"
68
+ :model-value="file.name === hoverfileName ? 'adtec-close' : 'adtec-success'"
69
+ style="color: var(--el-color-success); font-size: 14px"
70
+ :style="{
71
+ color:
72
+ file.name === hoverfileName ? 'var(--el-color-danger)' : 'var(--el-color-success)',
73
+ }"
74
+ ></el-icons>
75
+ </el-flex>
76
+ </el-flex>
77
+ </template>
78
+ </el-upload>
79
+ </template>
80
+
81
+ <script setup lang="ts">
82
+ import { UploadFilled } from '@element-plus/icons-vue'
83
+ import { computed, onMounted, ref } from 'vue'
84
+ import { ElMessage, type UploadFile, type UploadFiles, type UploadUserFile } from 'element-plus'
85
+ import type { ISysUploadFiles } from '../../interface/ISysUploadFiles'
86
+ //@ts-ignore
87
+ import useFileView from '../../hooks/useFileView.ts'
88
+ import documentApi from '../../api/DocumentApi.ts'
89
+
90
+ const { fileView: fileView } = useFileView()
91
+ const uploadHeaders = ref({
92
+ Authorization: '',
93
+ })
94
+ const ref_upload = ref()
95
+ const hoverfileName = ref('')
96
+ const props = defineProps({
97
+ /**
98
+ * @description 上传文件数量
99
+ * @default 1
100
+ */
101
+ limit: {
102
+ type: Number,
103
+ default: 1,
104
+ },
105
+
106
+ /**
107
+ * @description 上传文件类型
108
+ * @default ''
109
+ * @type {'images'|'document'|'txt'|'pdf'|'word'|'excel'|'ppt'}
110
+ */
111
+ accept: {
112
+ type: String,
113
+ default: '',
114
+ },
115
+ /**
116
+ * @description 业务类型
117
+ * @default 'default'
118
+ */
119
+ business: {
120
+ type: String,
121
+ default: 'default',
122
+ },
123
+ /**
124
+ * @description 业务id
125
+ * @default ''
126
+ */
127
+ businessId: {
128
+ type: String,
129
+ default: 'default',
130
+ },
131
+ /**
132
+ * 文件列表
133
+ */
134
+ uploadFilesList: {
135
+ type: Array<ISysUploadFiles>,
136
+ default: () => [],
137
+ },
138
+ /**
139
+ * @description 是否编辑状态
140
+ * @default 'true'
141
+ * @type {true|false}
142
+ */
143
+ isEdlt: {
144
+ type: Boolean,
145
+ default: true,
146
+ },
147
+ /**
148
+ * @description 文档上传是否默认关联,默认不关联
149
+ * @default 'false'
150
+ * @type {true|false}
151
+ */
152
+ association: {
153
+ type: Boolean,
154
+ default: false,
155
+ },
156
+ size: {
157
+ type: Number,
158
+ default: 50,
159
+ },
160
+ //附件宽度
161
+ itemWidth: {
162
+ type: String,
163
+ default: '100%',
164
+ },
165
+ })
166
+ const mousemove = (fileName: string) => {
167
+ hoverfileName.value = fileName
168
+ }
169
+ const mouseout = () => {
170
+ hoverfileName.value = ''
171
+ }
172
+ const getAccept = computed(() => {
173
+ if (props.accept === 'images') {
174
+ return '.jpg,.jpeg,.png,.gif,.bmp,.JPG,.JPEG,.PBG,.GIF,.BMP'
175
+ } else if (props.accept === 'document') {
176
+ return '.txt,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx'
177
+ } else if (props.accept === 'txt') {
178
+ return '.txt'
179
+ } else if (props.accept === 'pdf') {
180
+ return '.pdf'
181
+ } else if (props.accept === 'word') {
182
+ return '.doc,.docx'
183
+ } else if (props.accept === 'excel') {
184
+ return '.xls,.xlsx'
185
+ } else if (props.accept === 'ppt') {
186
+ return '.ppt,.pptx'
187
+ } else {
188
+ return ''
189
+ }
190
+ })
191
+ const getIcon = (fileName: string) => {
192
+ const type: string = fileName.split('.').pop() + ''
193
+ if ('.jpg,.jpeg,.png,.gif,.bmp,.JPG,.JPEG,.PBG,.GIF,.BMP'.includes(type)) {
194
+ return 'adtec-image'
195
+ } else if ('txt'.includes(type)) {
196
+ return 'adtec-text'
197
+ } else if ('pdf'.includes(type)) {
198
+ return 'adtec-pdf'
199
+ } else if ('doc,docx'.includes(type)) {
200
+ return 'adtec-word'
201
+ } else if ('xls,xlsx'.includes(type)) {
202
+ return 'adtec-excel'
203
+ } else if ('ppt,pptx'.includes(type)) {
204
+ return 'adtec-ppt'
205
+ } else {
206
+ return 'adtec-text'
207
+ }
208
+ }
209
+ const success = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
210
+ if (response.code === '0') {
211
+ props.uploadFilesList.push(response.data as ISysUploadFiles)
212
+ } else {
213
+ ElMessage.error(response.msg)
214
+ ref_upload.value?.handleRemove(uploadFile)
215
+ }
216
+ }
217
+ const beforeUpload = (file: File) => {
218
+ const f = props.uploadFilesList.find((c) => c.name === file.name)
219
+ if (f) {
220
+ ElMessage.warning(file.name + ',文件已存在')
221
+ return false
222
+ } else if (file.size > props.size * 1024 * 1024) {
223
+ ElMessage.warning('文件大小不能超过' + props.size + 'MB')
224
+ return false
225
+ }
226
+ return true
227
+ }
228
+ const fileClick = (file: UploadFile) => {
229
+ if (file.name === hoverfileName.value) {
230
+ ref_upload.value?.handleRemove(file)
231
+ } else {
232
+ preview(file)
233
+ }
234
+ }
235
+ const exceed = (files: File[], uploadFiles: UploadUserFile[]) => {
236
+ ElMessage.warning('最多上传' + props.limit + '个文件,上传文件数量已达到限制')
237
+ }
238
+ const error = () => {
239
+ ElMessage.error('上传失败')
240
+ }
241
+ const preview = async (uploadFile: UploadFile) => {
242
+ console.log('preview', uploadFile)
243
+ const file = props.uploadFilesList.find((c) => c.name === uploadFile.name)
244
+ if (file) {
245
+ //if ((uploadFile.response as any).code === '0') {
246
+ // const data = (uploadFile.response as any).data as ISysUploadFiles
247
+ fileView(file.id)
248
+ }
249
+ }
250
+ const remove = async (file: UploadFile) => {
251
+ // if ((file.response as any).code === '0') {
252
+ // const data = (file.response as any).data as ISysUploadFiles
253
+ const find = props.uploadFilesList.find((c) => c.name === file.name)
254
+ if (find) {
255
+ try {
256
+ await documentApi.delSysUploadFile(find.id)
257
+ props.uploadFilesList.splice(props.uploadFilesList.indexOf(find), 1)
258
+ } catch (error: any) {
259
+ ElMessage.error(error.msg)
260
+ }
261
+ }
262
+ // }
263
+ }
264
+ onMounted(() => {
265
+ uploadHeaders.value.Authorization = sessionStorage.getItem('Authorization') + ''
266
+ })
267
+ </script>
268
+ <style scoped lang="scss">
269
+ .file-class {
270
+ }
271
+ .file-class :hover {
272
+ color: var(--el-color-primary);
273
+ }
274
+ :deep {
275
+ .el-icon--upload {
276
+ margin-bottom: 0;
277
+ }
278
+ }
279
+ </style>
@@ -0,0 +1,158 @@
1
+ <!--创建人 丁盼-->
2
+ <!--说明: 文件查看-->
3
+ <!--创建时间: 2024/12/3 上午10:06-->
4
+ <!--修改时间: 2024/12/3 上午10:06-->
5
+ <template>
6
+ <!-- <el-dialog :title="title" v-model="model" @close="model = false" width="100%">-->
7
+ <Teleport to="body" v-if="model">
8
+ <div
9
+ style="
10
+ position: absolute;
11
+ z-index: 9999;
12
+ width: 100%;
13
+ height: 100%;
14
+ top: 0px;
15
+ background: rgb(0, 0, 0, 0.5);
16
+ text-align: center;
17
+ vertical-align: middle;
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: center;
21
+ "
22
+ >
23
+ <el-icon
24
+ @click="model = false"
25
+ style="
26
+ position: absolute;
27
+ top: 20px;
28
+ right: 20px;
29
+ font-size: 30px;
30
+ color: #fff;
31
+ cursor: pointer;
32
+ "
33
+ ><CircleClose
34
+ /></el-icon>
35
+
36
+ <DocumentEditor
37
+ id="docEditor"
38
+ :documentServerUrl="documentServerUrl"
39
+ :config="configcomp"
40
+ :events_onDocumentReady="onDocumentReady"
41
+ :onLoadComponentError="onLoadComponentError"
42
+ />
43
+ </div>
44
+ </Teleport>
45
+ <!-- </el-dialog>-->
46
+ </template>
47
+ <script setup lang="ts">
48
+ import { DocumentEditor } from '@onlyoffice/document-editor-vue'
49
+ import { computed, onBeforeMount, onMounted, ref } from 'vue'
50
+ import { userInfoStore } from '../../stores/userInfoStore'
51
+ import { useVModel } from '@vueuse/core'
52
+ import { CircleClose } from '@element-plus/icons-vue'
53
+ import { ElIcon } from 'element-plus'
54
+ const userinfo = userInfoStore()
55
+ const model = defineModel()
56
+ const documentServerUrl = ref('')
57
+ const documentServerCallbackUrl = ref('')
58
+ // 定义Props类型
59
+ const props = defineProps({
60
+ /**
61
+ * @default ''
62
+ * @description 文件标题
63
+ */
64
+ title: {
65
+ type: String,
66
+ default: '',
67
+ },
68
+ /**
69
+ * @default ''
70
+ * @description 文件Url地址
71
+ */
72
+ url: {
73
+ type: String,
74
+ default: '',
75
+ },
76
+ /**
77
+ * @default ''
78
+ * @description 文件id
79
+ */
80
+ fileId: {
81
+ type: String,
82
+ default: '',
83
+ },
84
+ /**
85
+ * @type {"view" | "edit"}
86
+ * @default ''
87
+ * @description 文件id
88
+ */
89
+ edit: {
90
+ type: String,
91
+ default: 'view',
92
+ },
93
+ })
94
+ const emit = defineEmits(['update:title', 'update:url', 'update:fileId', 'update:edit'])
95
+ const title = useVModel(props, 'title', emit)
96
+ const fileId = useVModel(props, 'fileId', emit)
97
+ const url = useVModel(props, 'url', emit)
98
+ const edit = useVModel(props, 'edit', emit)
99
+ const getFileType = () => {
100
+ if ((url.value + '').indexOf('.docx') !== -1 || (url.value + '').indexOf('.doc') !== -1) {
101
+ return 'docx'
102
+ } else if ((url.value + '').indexOf('.pdf') !== -1) {
103
+ return 'pdf'
104
+ } else if ((url.value + '').indexOf('.xlsx') !== -1 || (url.value + '').indexOf('.xls') !== -1) {
105
+ return 'xlsx'
106
+ } else if ((url.value + '').indexOf('.pptx') !== -1 || (url.value + '').indexOf('.pptx') !== -1) {
107
+ return 'pptx'
108
+ }
109
+ }
110
+ const getDocumentType = () => {
111
+ if ((url.value + '').indexOf('.docx') !== -1 || (url.value + '').indexOf('.doc') !== -1) {
112
+ return 'word'
113
+ } else if ((url.value + '').indexOf('.pdf') !== -1) {
114
+ return 'pdf'
115
+ } else if ((url.value + '').indexOf('.xlsx') !== -1 || (url.value + '').indexOf('.xls') !== -1) {
116
+ return 'cell'
117
+ } else if ((url.value + '').indexOf('.pptx') !== -1 || (url.value + '').indexOf('.pptx') !== -1) {
118
+ return 'slide'
119
+ }
120
+ }
121
+ const configcomp = computed(() => {
122
+ return {
123
+ document: {
124
+ fileType: getFileType(),
125
+ title: title.value,
126
+ url: url.value + '',
127
+ permissions: {
128
+ download: false,
129
+ edit: true,
130
+ },
131
+ },
132
+ documentType: getDocumentType(),
133
+ editorConfig: {
134
+ callbackUrl: documentServerCallbackUrl.value + '?fileId=' + fileId.value,
135
+ lang: 'zh-CN',
136
+ mode: edit.value,
137
+ // customization: {
138
+ // autosave: false,
139
+ // },
140
+ user: {
141
+ id: userinfo.getUserInfo.userCode,
142
+ name: userinfo.getUserInfo.userName,
143
+ },
144
+ },
145
+ height: '90%',
146
+ width: '90%',
147
+ }
148
+ })
149
+ const onDocumentReady = () => {}
150
+ const onLoadComponentError = () => {}
151
+ onBeforeMount(() => {
152
+ const config = JSON.parse(localStorage.getItem('systemConfig') + '')
153
+ documentServerUrl.value = config.documentServerUrl
154
+ documentServerCallbackUrl.value = config.documentServerCallbackUrl
155
+ })
156
+ onMounted(() => {})
157
+ </script>
158
+ <style scoped lang="scss"></style>
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <file-view
3
+ v-if="isVisible"
4
+ v-model="isVisible"
5
+ :title="fileTitle"
6
+ :url="viewUrl"
7
+ :fileId="fileId"
8
+ :edit="edit"
9
+ ></file-view>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import { ref } from 'vue'
14
+ const isVisible = ref(false)
15
+ //@ts-ignore
16
+ import 'vue-img-viewr/styles/index.css'
17
+ //@ts-ignore
18
+ import ImgViewr, { showImages } from 'vue-img-viewr'
19
+ import documentApi from '../../api/DocumentApi.ts'
20
+ import { ElMessage } from 'element-plus'
21
+ import framework from '../../api/framework.ts'
22
+ import FileView from './FileView.vue'
23
+ const fileTitle = ref('')
24
+ const viewUrl = ref('')
25
+ const fileId = ref('')
26
+ const edit = ref('view')
27
+
28
+ const viewFile = async (id: string) => {
29
+ //根据文件id获取文件信息
30
+ try {
31
+ const data = await documentApi.getUpLoadFilesVoById(id)
32
+ const data1 = await framework.getFileAccessAddress(data.id)
33
+ if ('.jpg,.jpeg,.png,.gif,.bmp,.JPG,.JPEG,.PBG,.GIF,.BMP'.includes(data.type)) {
34
+ showImages({
35
+ urls: [data1.url],
36
+ index: 0,
37
+ })
38
+ } else {
39
+ fileTitle.value = data.name
40
+ viewUrl.value = data1.url
41
+ fileId.value = data.id
42
+ isVisible.value = true
43
+ }
44
+ } catch (err: any) {
45
+ console.log(err)
46
+ ElMessage.error(err.msg)
47
+ }
48
+ }
49
+
50
+ defineExpose<{
51
+ viewFile: (id: string) => void
52
+ }>({
53
+ viewFile,
54
+ })
55
+ </script>
56
+
57
+ <style scoped></style>
@@ -0,0 +1,34 @@
1
+ import { ref, onMounted, onUnmounted, createApp } from 'vue'
2
+ import FileView from '../components/upload/FileViewComponents.vue'
3
+
4
+ const useFileView = () => {
5
+ const ref_fileView = ref(null)
6
+
7
+ const fileView = (id: string) => {
8
+ if (ref_fileView.value) {
9
+ //@ts-ignore
10
+ ref_fileView.value?.viewFile(id)
11
+ }
12
+ }
13
+
14
+ onMounted(() => {
15
+ const container = document.createElement('div')
16
+ document.body.appendChild(container)
17
+ //@ts-ignore
18
+ ref_fileView.value = createApp(FileView).mount(container)
19
+ onUnmounted(() => {
20
+ try {
21
+ //@ts-ignore
22
+ ref_fileView?.value.$destroy()
23
+ } catch {
24
+ /* empty */
25
+ }
26
+ document.body.removeChild(container)
27
+ })
28
+ })
29
+ return {
30
+ fileView,
31
+ }
32
+ }
33
+
34
+ export default useFileView
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Create by丁盼
3
+ * 说明: useMessageHooks
4
+ * 创建时间: 2024/9/3 下午5:27
5
+ * 修改时间: 2024/9/3 下午5:27
6
+ */
7
+ //@ts-ignore
8
+ import io from 'socket.io-client'
9
+ import type { ISysMessageVo } from '../interface/Message'
10
+ import { messageStore } from '../stores/messageStore'
11
+ import { ElMessage, ElNotification } from 'element-plus'
12
+ import { useEventBus } from '@vueuse/core'
13
+ export default function useMessageHooks() {
14
+ // @ts-ignore
15
+ const connect = () => {
16
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
17
+ // @ts-ignore
18
+ window.socketIo.connect()
19
+ }
20
+ const bus = useEventBus<ISysMessageVo>('messageClick')
21
+ const message = messageStore()
22
+ const createSocket = () => {
23
+ const socket = io(import.meta.env.VITE_SOCKETIO_URL, {
24
+ query: {
25
+ token: sessionStorage.getItem('Authorization'),
26
+ refreshToken: sessionStorage.getItem('refreshToken'),
27
+ sessionId: sessionStorage.getItem('sessionId'),
28
+ },
29
+ path: '/socket.io/',
30
+ transports: ['websocket', 'polling'],
31
+ autoConnect: false,
32
+ })
33
+
34
+ const server_response = (res: any) => {}
35
+ socket.off('server_response', server_response)
36
+ socket.on('server_response', server_response)
37
+ const connect = () => {
38
+ message.clearSysMessage()
39
+ //连接成功 获取离线数据UserExpireMessageOnEvent
40
+ socket.emit('UserExpireMessageOnEvent')
41
+ }
42
+ socket.off('connect', connect)
43
+ socket.on('connect', connect)
44
+ socket.on('user_Offline', () => {
45
+ console.log('user offline')
46
+ ElMessage.warning('您已被强制下线,即将跳转至登录页,请重新登录')
47
+ setTimeout(() => {
48
+ window.location.href = '/'
49
+ }, 2000)
50
+ })
51
+
52
+ const message_accept = (res: ISysMessageVo) => {
53
+ // if (res.params) {
54
+ // res.params = JSON.parse(res.params + '')
55
+ // }
56
+ let messageType = '通知'
57
+ if (res.messageType === 1) {
58
+ messageType = '消息'
59
+ } else if (res.messageType === 2) {
60
+ messageType = '待办'
61
+ }
62
+
63
+ const notif = ElNotification({
64
+ duration: 2000,
65
+ dangerouslyUseHTMLString: true,
66
+ onClick: () => {
67
+ bus.emit(res)
68
+ notif.close()
69
+ },
70
+ title: messageType,
71
+ message: res.title,
72
+ })
73
+ message.setSysMessage(res)
74
+ }
75
+ socket.off('message_accept', message_accept)
76
+ socket.on('message_accept', message_accept)
77
+ const expire_Message = (res: ISysMessageVo[]) => {
78
+ res.forEach((item) => {
79
+ message.setSysMessage(item)
80
+ })
81
+ }
82
+ socket.off('expire_Message', expire_Message)
83
+ socket.on('expire_Message', expire_Message)
84
+ //@ts-ignore
85
+ window.socketIo = socket
86
+ }
87
+ /**
88
+ * 接收方法注册
89
+ */
90
+ const registerResponseEvent = (eventName: string, event: Function) => {
91
+ //@ts-ignore
92
+ window.socketIo.on(eventName, event)
93
+ }
94
+ const close = () => {
95
+ //@ts-ignore
96
+ window.socketIo.close()
97
+ message.clearSysMessage()
98
+ }
99
+ /**
100
+ * 消息发送
101
+ * @param msg
102
+ */
103
+ const messageSend = (msg: ISysMessageVo) => {
104
+ //@ts-ignore
105
+ window.socketIo.emit('messageSend', JSON.stringify(msg))
106
+ }
107
+ /**
108
+ * 设置消息已读
109
+ * @constructor
110
+ */
111
+ const setMessageRead = (msg: ISysMessageVo) => {
112
+ //@ts-ignore
113
+ window.socketIo.emit('setMessageRead', JSON.stringify(msg))
114
+ message.setSysMessageStatus(msg)
115
+ }
116
+ const setMessageReadAll = () => {
117
+ message.getMessageList.forEach((item) => {
118
+ //@ts-ignore
119
+ window.socketIo.emit('setMessageRead', JSON.stringify(item))
120
+ })
121
+ message.clearSysMessage()
122
+ }
123
+ return {
124
+ close,
125
+ connect,
126
+ createSocket,
127
+ messageSend,
128
+ registerResponseEvent,
129
+ setMessageRead,
130
+ setMessageReadAll,
131
+ }
132
+ }
@@ -0,0 +1,19 @@
1
+ import { type Ref, ref } from 'vue'
2
+ import { cloneDeep } from 'lodash-es'
3
+
4
+ /**
5
+ * 创建人 胡啸东
6
+ * 说明: 用于重置对象
7
+ * 创建时间: 2024/12/18 下午3:57
8
+ * 修改时间: 2024/12/18 下午3:57
9
+ */
10
+
11
+ export function useResetRefHooks<T>(value: T): [Ref<T>, () => void] {
12
+ const initValue = cloneDeep(value)
13
+ const state = ref(value)
14
+ const reset = () => {
15
+ state.value = cloneDeep(initValue)
16
+ }
17
+ //@ts-ignore
18
+ return [state, reset]
19
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Create by丁盼
3
+ * 说明: IUserPermissionVo
4
+ * 创建时间: 2025/1/15 11:41
5
+ * 修改时间: 2025/1/15 11:41
6
+ */
7
+ import type { ISysMenuInfoVo } from '../interface/ISysMenuInfoVo'
8
+ export interface IUserPermissionVo {
9
+ id: string
10
+ /**
11
+ * 部门Id
12
+ */
13
+ orgId: string
14
+ /**
15
+ * 用户编码
16
+ */
17
+ userCode: string
18
+ /**
19
+ * 用户名称
20
+ */
21
+ userName: string
22
+ /**
23
+ * 用户类型
24
+ */
25
+ userType: string
26
+ email: string
27
+ phonenumber: string
28
+ sex: string
29
+ avatar: string
30
+ status: string
31
+ remark: string
32
+ menuList: ISysMenuInfoVo[]
33
+ menuTreeList: ISysMenuInfoVo[]
34
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Create by丁盼
3
+ * 说明: 消息接口
4
+ * 创建时间: 2024/9/4 上午11:30
5
+ * 修改时间: 2024/9/4 上午11:30
6
+ */
7
+
8
+ import type { MessageViewType, MessageType } from '../interface/enum/MessageEnum.ts'
9
+
10
+ /**
11
+ * 消息参数接口
12
+ */
13
+ export interface IParameter {
14
+ code: string
15
+ value: any
16
+ }
17
+ /**
18
+ * 消息发送接口
19
+ */
20
+ export interface ISysMessageVo {
21
+ id?: string
22
+ /**
23
+ * 当前用户Id
24
+ */
25
+ userId: string
26
+ /**
27
+ * 当前用户
28
+ */
29
+ userName: string
30
+ /**
31
+ * 消息内容
32
+ */
33
+ content: string
34
+ /**
35
+ * 消息标题
36
+ */
37
+ title: string
38
+ /**
39
+ * 消息类型
40
+ */
41
+ messageType: MessageType
42
+ /**
43
+ * 消息参数
44
+ */
45
+ params?: IParameter[]
46
+ /**
47
+ * 消息查看方式
48
+ */
49
+ viewType: MessageViewType
50
+ /**
51
+ * 消息链接
52
+ */
53
+ linkModelPath: string
54
+ /**
55
+ * 消息接收人
56
+ */
57
+ receiveUserIds: string[]
58
+ /**
59
+ * 自定义接收方法名
60
+ */
61
+ eventName?: string
62
+ /**
63
+ * 过期时间,默认7天
64
+ */
65
+ expireTime?: number
66
+ createTime?: Date
67
+ receiveId?: string
68
+ receiveState?: number
69
+ }
@@ -7,7 +7,7 @@
7
7
  /**
8
8
  * flex横向布局枚举
9
9
  */
10
- export enum justifyContentEnum {
10
+ export enum justifyContentEnum {
11
11
  /**
12
12
  * 子元素在容器内左对齐
13
13
  */
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Create by丁盼
3
+ * 说明: 消息枚举定义
4
+ * 创建时间: 2024/9/4 上午11:36
5
+ * 修改时间: 2024/9/4 上午11:36
6
+ */
7
+ /**
8
+ * 消息查看类型
9
+ */
10
+ export enum MessageViewType {
11
+ /**
12
+ * 默认
13
+ */
14
+ default = 0,
15
+ /**
16
+ * 打开dialog
17
+ */
18
+ form = 1,
19
+ /**
20
+ * 打开菜单
21
+ */
22
+ menu = 2,
23
+ }
24
+
25
+ /**
26
+ * 消息类型
27
+ */
28
+ export enum MessageType {
29
+ /**
30
+ * 通知
31
+ */
32
+ notice = 0,
33
+ /**
34
+ * 消息
35
+ */
36
+ message = 1,
37
+ /**
38
+ * 待办
39
+ */
40
+ toDo = 2,
41
+ }
@@ -0,0 +1,49 @@
1
+ import { defineStore } from 'pinia'
2
+ import type { ISysMessageVo } from '../interface/Message.ts'
3
+
4
+ /**
5
+ * Create by丁盼
6
+ * 说明: 用户消息Store
7
+ * 创建时间: 2024/9/4 下午4:25
8
+ * 修改时间: 2024/9/4 下午4:25
9
+ */
10
+ export const messageStore = defineStore({
11
+ id: 'messageStore',
12
+ state: () => ({
13
+ //@ts-ignore
14
+ messageList: [] as ISysMessageVo[],
15
+ }),
16
+ getters: {
17
+ /**
18
+ * 获取用户消息
19
+ */
20
+ getMessageList(): ISysMessageVo[] {
21
+ return this.messageList
22
+ },
23
+ },
24
+ actions: {
25
+ /**
26
+ * 设置系统消息
27
+ * @param sysMessage
28
+ */
29
+ setSysMessage(sysMessage: ISysMessageVo) {
30
+ this.messageList.unshift(sysMessage)
31
+ },
32
+ /**
33
+ * 清空消息
34
+ */
35
+ clearSysMessage() {
36
+ this.messageList = []
37
+ },
38
+ /**
39
+ * 设置消息状态
40
+ * @param sysMessage
41
+ */
42
+ setSysMessageStatus(sysMessage: ISysMessageVo) {
43
+ const index = this.messageList.findIndex((item) => item.id === sysMessage.id)
44
+ if (index !== -1) {
45
+ this.messageList.splice(index, 1)
46
+ }
47
+ },
48
+ },
49
+ })
@@ -0,0 +1,22 @@
1
+ import { createPinia } from 'pinia'
2
+ import { storePlugin } from 'pinia-plugin-store'
3
+ import Utf8 from 'crypto-js/enc-utf8'
4
+ import Base64 from 'crypto-js/enc-base64'
5
+ const store = createPinia()
6
+ function encrypt(value: string): string {
7
+ return Base64.stringify(Utf8.parse(value))
8
+ }
9
+ function decrypt(value: string): string {
10
+ return Base64.parse(value).toString(Utf8)
11
+ }
12
+
13
+ const plugin = storePlugin({
14
+ stores: ['userInfoStore','messageStore'],
15
+ // use alone storage
16
+ // stores: [{name:'theme_store',storage: localStorage}]
17
+ storage: sessionStorage, //default storage
18
+ encrypt,
19
+ decrypt
20
+ })
21
+ store.use(plugin)
22
+ export default store
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Create by丁盼
3
+ * 说明: userInfoStore
4
+ * 创建时间: 2025/1/15 11:40
5
+ * 修改时间: 2025/1/15 11:40
6
+ */
7
+ import { defineStore } from 'pinia'
8
+ import type { IUserPermissionVo } from '../interface/IUserPermissionVo'
9
+
10
+ export const userInfoStore = defineStore({
11
+ id: 'userInfoStore',
12
+ state: () => ({
13
+ //@ts-ignore
14
+ user: null as IUserPermissionVo
15
+ }),
16
+ getters: {
17
+ getUserInfo(): IUserPermissionVo {
18
+ return this.user as IUserPermissionVo
19
+ }
20
+ },
21
+ actions: {
22
+ setUserInfo(userInfo: IUserPermissionVo) {
23
+ //@ts-ignore
24
+ this.user = userInfo
25
+ },
26
+ clear() {
27
+ //@ts-ignore
28
+ this.user = null
29
+ }
30
+ }
31
+ })
@@ -1,12 +0,0 @@
1
- import { ref, computed } from 'vue'
2
- import { defineStore } from 'pinia'
3
-
4
- export const useCounterStore = defineStore('counter', () => {
5
- const count = ref(0)
6
- const doubleCount = computed(() => count.value * 2)
7
- function increment() {
8
- count.value++
9
- }
10
-
11
- return { count, doubleCount, increment }
12
- })