create-jnrs-template-vue 1.2.2 → 1.2.4

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 (37) hide show
  1. package/jnrs-template-vue/.env.development +1 -1
  2. package/jnrs-template-vue/index.html +1 -1
  3. package/jnrs-template-vue/package.json +3 -4
  4. package/jnrs-template-vue/public/system/menu.json +11 -2
  5. package/jnrs-template-vue/src/App.vue +1 -3
  6. package/jnrs-template-vue/src/api/common/index.ts +2 -2
  7. package/jnrs-template-vue/src/api/demos/index.ts +85 -43
  8. package/jnrs-template-vue/src/api/system/index.ts +20 -10
  9. package/jnrs-template-vue/src/api/user/index.ts +2 -2
  10. package/jnrs-template-vue/src/assets/styles/index.scss +0 -24
  11. package/jnrs-template-vue/src/assets/styles/init.scss +24 -0
  12. package/jnrs-template-vue/src/assets/styles/root.scss +4 -0
  13. package/jnrs-template-vue/src/components/common/CardTable.vue +89 -0
  14. package/jnrs-template-vue/src/components/common/DictTag.vue +8 -4
  15. package/jnrs-template-vue/src/components/common/ImageView.vue +16 -7
  16. package/jnrs-template-vue/src/components/common/PdfView.vue +14 -5
  17. package/jnrs-template-vue/src/components/select/SelectManager.vue +2 -2
  18. package/jnrs-template-vue/src/layout/SideMenu.vue +0 -1
  19. package/jnrs-template-vue/src/layout/TopHeader.vue +7 -14
  20. package/jnrs-template-vue/src/locales/index.ts +1 -1
  21. package/jnrs-template-vue/src/types/webSocket.ts +19 -0
  22. package/jnrs-template-vue/src/utils/file.ts +36 -1
  23. package/jnrs-template-vue/src/views/demos/crud/index.vue +57 -32
  24. package/jnrs-template-vue/src/views/demos/simpleTable/index.vue +41 -0
  25. package/jnrs-template-vue/src/views/demos/unitTest/RequestPage.vue +2 -2
  26. package/jnrs-template-vue/src/views/demos/unitTest/index.vue +26 -2
  27. package/jnrs-template-vue/src/views/login/index.vue +18 -15
  28. package/jnrs-template-vue/src/views/system/dict/index.vue +63 -76
  29. package/jnrs-template-vue/src/views/system/menu/index.vue +42 -54
  30. package/jnrs-template-vue/src/views/system/mine/baseInfo.vue +26 -59
  31. package/jnrs-template-vue/src/views/system/role/index.vue +20 -29
  32. package/jnrs-template-vue/src/views/visual/index.vue +130 -15
  33. package/jnrs-template-vue/vite.config.ts +0 -1
  34. package/jnrs-template-vue/viteMockServe/fail.ts +12 -0
  35. package/package.json +1 -1
  36. package/jnrs-template-vue/src/composables/base/useAvatar.ts +0 -36
  37. package/jnrs-template-vue/src/composables/tools/useMouseSelection.ts +0 -150
@@ -1,12 +1,11 @@
1
1
  <script setup lang="ts">
2
+ import type { DictItem } from '@jnrs/shared'
2
3
  import { ElMessage } from 'element-plus'
3
4
  import { ref, onActivated } from 'vue'
4
5
  import { DictApi, DictDetailApi, DictChangeApi } from '@/api/system'
5
- import { useReactivityTableHeight } from '@jnrs/vue-core/composables'
6
- import type { DictItem } from '@jnrs/shared'
7
6
  import { hasPermission } from '@/utils/permissions'
7
+ import { JnTable } from '@jnrs/vue-core/components'
8
8
 
9
- const { maxHeight } = useReactivityTableHeight({ className: 'el_table_dict', bottomGap: 0 })
10
9
  const PERMISSION_EDIT = ['dict:edit']
11
10
  const loading = ref(false)
12
11
  const tableData = ref<DictItem[]>()
@@ -73,80 +72,68 @@ const editKeyValue = (row: DictItem) => {
73
72
  </script>
74
73
 
75
74
  <template>
76
- <div class="main">
77
- <el-card shadow="never">
78
- <template #header>
79
- <div class="card_header">
80
- <h3>字典管理</h3>
81
- </div>
82
- </template>
83
- <el-table
84
- class="el_table_dict"
85
- :data="tableData"
86
- :height="maxHeight"
87
- scrollbar-always-on
88
- border
89
- v-loading="loading"
90
- row-key="id"
91
- @expand-change="handleExpandChange"
92
- >
93
- <el-table-column prop="dictName" label="字典名" />
94
- <el-table-column prop="describe" label="说明" />
95
- <el-table-column type="expand" fixed="right" label="字典值" width="100">
96
- <template #default="scope">
97
- <div class="table_expand animation15" style="animation-duration: 0.5s; animation-delay: 0s">
98
- <div class="table_expand_top">
99
- <h5>字典值列表</h5>
100
- </div>
101
- <el-table :data="scope.row.options" :border="true" size="small" row-key="value">
102
- <el-table-column label="value" prop="value" width="100" align="center"></el-table-column>
103
- <el-table-column label="label" prop="label">
104
- <template #default="optionScope">
105
- <el-input
106
- v-model="optionScope.row.label"
107
- maxlength="20"
108
- :disabled="!hasPermission(PERMISSION_EDIT)"
109
- />
110
- </template>
111
- </el-table-column>
112
- <el-table-column label="颜色" prop="displayColor">
113
- <template #default="optionScope">
114
- <el-color-picker
115
- v-model="optionScope.row.displayColor"
116
- :predefine="predefineColors"
117
- :disabled="!hasPermission(PERMISSION_EDIT)"
118
- />
119
- <span style="margin-left: 10px">
120
- {{ optionScope.row.displayColor || '无' }}
121
- </span>
122
- </template>
123
- </el-table-column>
124
- <el-table-column prop="sequence" label="排序" width="180" align="center">
125
- <template #default="optionScope">
126
- <el-input-number
127
- v-model="optionScope.row.sequence"
128
- :min="1"
129
- :max="999"
130
- :step="1"
131
- controls-position="right"
132
- step-strictly
133
- :disabled="!hasPermission(PERMISSION_EDIT)"
134
- style="width: 140px"
135
- />
136
- </template>
137
- </el-table-column>
138
- <el-table-column label="操作" width="100" align="center" fixed="right" v-permissions="PERMISSION_EDIT">
139
- <template #default="optionScope">
140
- <el-button type="success" size="small" @click="editKeyValue(optionScope.row)">确认修改</el-button>
141
- </template>
142
- </el-table-column>
143
- </el-table>
75
+ <el-card v-loading="loading">
76
+ <template #header>
77
+ <span>字典管理</span>
78
+ </template>
79
+
80
+ <JnTable :data="tableData" @expand-change="handleExpandChange">
81
+ <el-table-column prop="dictName" label="字典名" />
82
+ <el-table-column prop="describe" label="说明" />
83
+ <el-table-column type="expand" fixed="right" label="字典值" width="100">
84
+ <template #default="scope">
85
+ <div class="table_expand">
86
+ <div class="table_expand_top">
87
+ <h5>字典值列表</h5>
144
88
  </div>
145
- </template>
146
- </el-table-column>
147
- </el-table>
148
- </el-card>
149
- </div>
89
+ <el-table :data="scope.row.options" :border="true" size="small" row-key="value">
90
+ <el-table-column label="value" prop="value" width="100" align="center"></el-table-column>
91
+ <el-table-column label="label" prop="label">
92
+ <template #default="optionScope">
93
+ <el-input
94
+ v-model="optionScope.row.label"
95
+ maxlength="20"
96
+ :disabled="!hasPermission(PERMISSION_EDIT)"
97
+ />
98
+ </template>
99
+ </el-table-column>
100
+ <el-table-column label="颜色" prop="displayColor">
101
+ <template #default="optionScope">
102
+ <el-color-picker
103
+ v-model="optionScope.row.displayColor"
104
+ :predefine="predefineColors"
105
+ :disabled="!hasPermission(PERMISSION_EDIT)"
106
+ />
107
+ <span style="margin-left: 10px">
108
+ {{ optionScope.row.displayColor || '无' }}
109
+ </span>
110
+ </template>
111
+ </el-table-column>
112
+ <el-table-column prop="sequence" label="排序" width="180" align="center">
113
+ <template #default="optionScope">
114
+ <el-input-number
115
+ v-model="optionScope.row.sequence"
116
+ :min="1"
117
+ :max="999"
118
+ :step="1"
119
+ controls-position="right"
120
+ step-strictly
121
+ :disabled="!hasPermission(PERMISSION_EDIT)"
122
+ style="width: 140px"
123
+ />
124
+ </template>
125
+ </el-table-column>
126
+ <el-table-column label="操作" width="100" align="center" fixed="right" v-permissions="PERMISSION_EDIT">
127
+ <template #default="optionScope">
128
+ <el-button type="success" size="small" @click="editKeyValue(optionScope.row)">确认修改</el-button>
129
+ </template>
130
+ </el-table-column>
131
+ </el-table>
132
+ </div>
133
+ </template>
134
+ </el-table-column>
135
+ </JnTable>
136
+ </el-card>
150
137
  </template>
151
138
 
152
139
  <style scoped lang="scss">
@@ -1,65 +1,53 @@
1
1
  <script setup lang="ts">
2
2
  import { ref } from 'vue'
3
3
  import { useMenuStore } from '@jnrs/vue-core/pinia'
4
- import { useReactivityTableHeight } from '@jnrs/vue-core/composables'
4
+ import { JnTable } from '@jnrs/vue-core/components'
5
5
 
6
- const { maxHeight } = useReactivityTableHeight({ className: 'el_table_menu', bottomGap: 0 })
7
6
  const loading = ref(false)
8
7
 
9
8
  const { menus } = useMenuStore()
10
9
  </script>
11
10
 
12
11
  <template>
13
- <div>
14
- <el-card shadow="never">
15
- <template #header>
16
- <div class="card_header">
17
- <h3>菜单管理</h3>
18
- </div>
19
- </template>
20
- <el-table
21
- class="el_table_menu"
22
- :data="menus"
23
- :height="maxHeight"
24
- scrollbar-always-on
25
- row-key="meta.uuid"
26
- border
27
- v-loading="loading"
28
- >
29
- <el-table-column prop="meta.title" label="标题" min-width="120" header-align="center" />
30
- <el-table-column prop="icon" label="图标" width="60" align="center">
31
- <template #default="{ row }">
32
- <el-icon v-if="row.meta.icon"><component :is="row.meta.icon" /></el-icon>
33
- </template>
34
- </el-table-column>
35
- <el-table-column prop="path" label="路由地址" min-width="120" header-align="center" />
36
- <el-table-column prop="component" label="component path" min-width="120" header-align="center" />
37
- <el-table-column prop="redirect" label="redirect" min-width="120" header-align="center" />
38
- <el-table-column prop="editRole" label="权限标识" min-width="120" header-align="center">
39
- <template #default="{ row }">
40
- <span v-if="!row.meta.permissions" style="color: #999">auto</span>
41
- <span v-else>{{ row.meta.permissions }}</span>
42
- </template>
43
- </el-table-column>
44
- <el-table-column prop="type" label="类型" width="80" align="center">
45
- <template #default="{ row }">
46
- <el-tag type="primary" v-if="row.path">菜单</el-tag>
47
- <el-tag type="success" v-else>目录</el-tag>
48
- </template>
49
- </el-table-column>
50
- <el-table-column prop="type" label="NoAuth" width="80" align="center">
51
- <template #default="{ row }">
52
- <el-tag type="danger" v-if="row.meta.noAuth">否</el-tag>
53
- <el-tag type="success" v-else>是</el-tag>
54
- </template>
55
- </el-table-column>
56
- <el-table-column prop="type" label="Global" width="80" align="center">
57
- <template #default="{ row }">
58
- <el-tag type="success" v-if="row.meta.global">是</el-tag>
59
- <el-tag type="primary" v-else>否</el-tag>
60
- </template>
61
- </el-table-column>
62
- </el-table>
63
- </el-card>
64
- </div>
12
+ <el-card v-loading="loading">
13
+ <template #header>
14
+ <span>菜单管理</span>
15
+ </template>
16
+
17
+ <JnTable :data="menus" row-key="meta.uuid" :showScrollbar="true">
18
+ <el-table-column prop="meta.title" label="标题" min-width="120" header-align="center" />
19
+ <el-table-column prop="icon" label="图标" width="60" align="center">
20
+ <template #default="{ row }">
21
+ <el-icon v-if="row.meta.icon"><component :is="row.meta.icon" /></el-icon>
22
+ </template>
23
+ </el-table-column>
24
+ <el-table-column prop="path" label="路由地址" min-width="120" header-align="center" />
25
+ <el-table-column prop="component" label="component path" min-width="120" header-align="center" />
26
+ <el-table-column prop="redirect" label="redirect" min-width="120" header-align="center" />
27
+ <el-table-column prop="editRole" label="权限标识" min-width="120" header-align="center">
28
+ <template #default="{ row }">
29
+ <span v-if="!row.meta.permissions" style="color: #999">auto</span>
30
+ <span v-else>{{ row.meta.permissions }}</span>
31
+ </template>
32
+ </el-table-column>
33
+ <el-table-column prop="type" label="类型" width="80" align="center">
34
+ <template #default="{ row }">
35
+ <el-tag type="primary" v-if="row.path">菜单</el-tag>
36
+ <el-tag type="success" v-else>目录</el-tag>
37
+ </template>
38
+ </el-table-column>
39
+ <el-table-column prop="type" label="NoAuthApi" width="80" align="center">
40
+ <template #default="{ row }">
41
+ <el-tag type="danger" v-if="row.meta.noAuth">否</el-tag>
42
+ <el-tag type="success" v-else>是</el-tag>
43
+ </template>
44
+ </el-table-column>
45
+ <el-table-column prop="type" label="Global" width="80" align="center">
46
+ <template #default="{ row }">
47
+ <el-tag type="success" v-if="row.meta.global">是</el-tag>
48
+ <el-tag type="primary" v-else>否</el-tag>
49
+ </template>
50
+ </el-table-column>
51
+ </JnTable>
52
+ </el-card>
65
53
  </template>
@@ -1,18 +1,16 @@
1
1
  <script setup lang="ts">
2
+ import type { FormInstance } from 'element-plus'
2
3
  import { ref, onMounted } from 'vue'
3
- import { storeToRefs } from 'pinia'
4
- import { ElMessage } from 'element-plus'
5
- import type { UploadProps } from 'element-plus'
6
4
  import { useAuthStore } from '@jnrs/vue-core/pinia'
7
- import { useAvatar } from '@/composables/base/useAvatar'
8
5
  import { getDictList } from '@/utils/packages'
9
- import type { User } from '@jnrs/shared'
6
+ import { JnFileUpload } from '@jnrs/vue-core/components'
7
+ import { AvatarChangeApi } from '@/api/system'
8
+ import { objectMatchAssign } from '@jnrs/shared'
10
9
 
11
- const { userInfo, token } = storeToRefs(useAuthStore())
12
- const { avatar } = useAvatar()
13
- const loading = ref(false)
14
- const ruleFormRef = ref()
15
- const ruleForm = ref<User>({
10
+ const { userInfo } = useAuthStore()
11
+ // const loading = ref(false)
12
+ const ruleFormRef = ref<FormInstance>()
13
+ const ruleForm = ref({
16
14
  id: 0,
17
15
  account: '',
18
16
  name: '',
@@ -20,7 +18,8 @@ const ruleForm = ref<User>({
20
18
  jobTitle: 0,
21
19
  workgroup: '',
22
20
  role: 0,
23
- avatarFileName: ''
21
+ avatarFileName: '',
22
+ file: []
24
23
  })
25
24
  const rules = ref({
26
25
  // account: { required: true, message: '请输入', trigger: 'change' },
@@ -29,44 +28,14 @@ const rules = ref({
29
28
  // workNo: { required: true, message: '请输入', trigger: 'change' },
30
29
  })
31
30
 
32
- interface ApiResponse {
33
- code: number
34
- message: string
35
- data: string
36
- }
37
-
38
31
  onMounted(() => {
39
- if (userInfo.value) {
40
- ruleForm.value = userInfo.value
41
- }
32
+ const matched = objectMatchAssign(ruleForm.value, userInfo)
33
+ ruleForm.value = matched
42
34
  })
43
-
44
- const handleAvatarSuccess: UploadProps['onSuccess'] = (response: ApiResponse) => {
45
- loading.value = false
46
- if (userInfo.value && response.code === 0) {
47
- userInfo.value.avatarFileName = response.data
48
- ElMessage.success({ message: '头像上传成功' })
49
- }
50
- }
51
-
52
- const handleProgress = () => {
53
- loading.value = true
54
- }
55
-
56
- const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
57
- if (rawFile.type.indexOf('image/') < 0) {
58
- ElMessage.error('上传头像只能是图片格式!')
59
- return false
60
- } else if (rawFile.size / 1024 / 1024 > 10) {
61
- ElMessage.error('上传头像图片大小不能超过10MB!')
62
- return false
63
- }
64
- return true
65
- }
66
35
  </script>
67
36
 
68
37
  <template>
69
- <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" disabled>
38
+ <el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="auto" :disabled="true">
70
39
  <el-form-item label="登录账号" prop="account">
71
40
  <el-input v-model.trim="ruleForm.account" style="width: 200px" />
72
41
  </el-form-item>
@@ -94,23 +63,21 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
94
63
  <el-option :label="item.label" :value="item.value" v-for="(item, index) in getDictList('role')" :key="index" />
95
64
  </el-select>
96
65
  </el-form-item>
97
- <el-form-item label="头像" prop="avatarFileName" class="uploader_item">
98
- <el-upload
99
- action="/api/user/avatar"
100
- :headers="{
101
- Authorization: 'Bearer ' + token
102
- }"
103
- :show-file-list="false"
104
- :before-upload="beforeAvatarUpload"
105
- :on-progress="handleProgress"
106
- :on-success="handleAvatarSuccess"
107
- >
108
- <img v-if="avatar" :src="avatar" class="uploader_avatar" />
109
- <el-icon v-else class="uploader_icon"><Plus /></el-icon>
110
- </el-upload>
66
+ <el-form-item label="头像" prop="file" class="uploader_item">
67
+ <JnFileUpload
68
+ v-model="ruleForm.file"
69
+ :formRef="ruleFormRef"
70
+ validateFieldName="newImageFiles"
71
+ accept=".png,.jpg,.bmp,.gif"
72
+ :fileSizeMb="50"
73
+ :limit="1"
74
+ :showFileList="false"
75
+ :autoUploadApi="AvatarChangeApi"
76
+ style="width: 500px"
77
+ />
111
78
  </el-form-item>
112
79
  <!-- <el-form-item>
113
- <el-button class="form_submit" :loading="loading" type="primary" @click="submitForm(ruleFormRef)">
80
+ <el-button class="form_submit" :loading="loading" type="primary" @click="submitForm">
114
81
  保存修改
115
82
  </el-button>
116
83
  </el-form-item> -->
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, onMounted } from 'vue'
3
3
  import { RoleApi } from '@/api/system'
4
+ import { JnTable } from '@jnrs/vue-core/components'
4
5
 
5
6
  const loading = ref(false)
6
7
  const tableData = ref()
@@ -18,33 +19,23 @@ onMounted(() => {
18
19
  </script>
19
20
 
20
21
  <template>
21
- <div class="main">
22
- <el-card shadow="never">
23
- <template #header>
24
- <div class="card_header">
25
- <h3>角色管理</h3>
26
- </div>
27
- </template>
28
- <el-table
29
- class="el_table_role"
30
- header-cell-class-name="tableData_header_cell"
31
- :data="tableData"
32
- scrollbar-always-on
33
- border
34
- v-loading="loading"
35
- >
36
- <el-table-column prop="label" label="角色名称" width="200" align="center" />
37
- <el-table-column prop="value" label="值" width="200" align="center">
38
- <template #default="{ row }">
39
- {{ row.value + ' [' + typeof row.value + ']' }}
40
- </template>
41
- </el-table-column>
42
- <el-table-column prop="permissions" label="可用权限" header-align="center">
43
- <template #default="{ row }">
44
- {{ row.permissions }}
45
- </template>
46
- </el-table-column>
47
- </el-table>
48
- </el-card>
49
- </div>
22
+ <el-card v-loading="loading">
23
+ <template #header>
24
+ <span>角色管理</span>
25
+ </template>
26
+
27
+ <JnTable :data="tableData">
28
+ <el-table-column prop="label" label="角色名称" width="200" align="center" />
29
+ <el-table-column prop="value" label="值" width="200" align="center">
30
+ <template #default="{ row }">
31
+ {{ row.value + ' [' + typeof row.value + ']' }}
32
+ </template>
33
+ </el-table-column>
34
+ <el-table-column prop="permissions" label="可用权限" header-align="center">
35
+ <template #default="{ row }">
36
+ {{ row.permissions }}
37
+ </template>
38
+ </el-table-column>
39
+ </JnTable>
40
+ </el-card>
50
41
  </template>
@@ -1,22 +1,59 @@
1
1
  <script setup lang="ts">
2
- const goLogin = () => {
3
- // removeAll()
4
- window.location.href = '/login'
5
- }
6
- const goHome = () => {
7
- window.location.href = '/'
8
- }
9
- const goBack = () => {
10
- window.history.go(-1)
11
- }
2
+ import type { MsgIdMessage, TypeDataMessage } from '@/types/webSocket'
3
+ import { isMsgIdMessage, isTypeDataMessage } from '@/types/webSocket'
4
+ import { storeToRefs } from 'pinia'
5
+ import { useWebSocket } from '@jnrs/vue-core/composables'
6
+ import { useRouter } from '@jnrs/vue-core/router'
7
+ import { useSystemStore } from '@jnrs/vue-core/pinia'
8
+
9
+ const router = useRouter()
10
+ const systemStore = useSystemStore()
11
+ const { documentFullscreen } = storeToRefs(systemStore)
12
+ const { toggleFullScreen } = systemStore
13
+
14
+ const { isLoading, wsStateInfo } = useWebSocket({
15
+ url: '/ws/monitor',
16
+ connectionTimeoutDuration: 3_000, // 修改仅为测试
17
+ onMessage: (rawMessage: unknown) => {
18
+ if (isMsgIdMessage(rawMessage)) {
19
+ const msg = rawMessage as MsgIdMessage
20
+ if (msg.msgId && msg.d && typeof msg.d === 'object') {
21
+ // console.log('接收 msgId 数据:', msg)
22
+ }
23
+ } else if (isTypeDataMessage(rawMessage)) {
24
+ const msg = rawMessage as TypeDataMessage
25
+ if (msg.type && msg.data && typeof msg.data === 'object') {
26
+ // console.log('接收 type 数据:', msg)
27
+ }
28
+ }
29
+ }
30
+ })
12
31
  </script>
13
32
 
14
33
  <template>
15
- <div>visual</div>
16
- <div class="main_mid_btn">
17
- <el-button @click="goLogin" style="margin-right: 20px">重新登录</el-button>
18
- <el-button type="primary" plain @click="goHome" style="margin-right: 20px">返回首页</el-button>
19
- <el-button type="primary" @click="goBack">返回上一页</el-button>
34
+ <div
35
+ class="visual"
36
+ v-loading="isLoading"
37
+ element-loading-background="rgba(0,0,0,.5)"
38
+ element-loading-text="网络加载中..."
39
+ >
40
+ <div class="visual_head">
41
+ <div class="visual_head_left">
42
+ <div class="visual_title">
43
+ <b>数字孪生看板</b>
44
+ <span>{{ wsStateInfo }}</span>
45
+ </div>
46
+ </div>
47
+ <div class="visual_head_right">
48
+ <span class="btn" @click="toggleFullScreen">
49
+ {{ !documentFullscreen ? '启用全屏' : '退出全屏' }}
50
+ </span>
51
+ <span class="btn" @click="router.push('/')">返回首页</span>
52
+ </div>
53
+ </div>
54
+ <div class="visual_canvas">
55
+ <i>canvas</i>
56
+ </div>
20
57
  </div>
21
58
  </template>
22
59
 
@@ -25,4 +62,82 @@ const goBack = () => {
25
62
  @function px2vw($px) {
26
63
  @return math.div($px, 1920) * 100vw;
27
64
  }
65
+
66
+ .visual {
67
+ position: relative;
68
+ width: 100%;
69
+ height: 100%;
70
+ font-size: px2vw(18);
71
+ overflow: hidden;
72
+ user-select: none;
73
+
74
+ .visual_head {
75
+ position: absolute;
76
+ z-index: 10;
77
+ display: flex;
78
+ justify-content: space-between;
79
+ align-items: top;
80
+ width: 100%;
81
+ padding: px2vw(10);
82
+ color: #fff;
83
+
84
+ .visual_title {
85
+ display: inline-flex;
86
+ align-items: center;
87
+ font-size: px2vw(24);
88
+ height: px2vw(30);
89
+ background: #000;
90
+ border: px2vw(2) solid #f2f2f2;
91
+ margin: 0 0 px2vw(5) 0;
92
+ overflow: hidden;
93
+
94
+ b {
95
+ display: inline-block;
96
+ padding: 0 px2vw(5);
97
+ font-size: px2vw(24);
98
+ background: #f2f2f2;
99
+ color: #000;
100
+ }
101
+
102
+ span {
103
+ padding: 0 px2vw(8);
104
+ color: #f2f2f2;
105
+ box-sizing: border-box;
106
+ }
107
+ }
108
+
109
+ .visual_head_right {
110
+ .btn {
111
+ align-items: center;
112
+ padding: 0 px2vw(8);
113
+ color: #f2f2f2;
114
+ background: var(--jnrs-color-primary);
115
+ border-radius: px2vw(2);
116
+ margin: 0 px2vw(2);
117
+ transition: all 0.25s ease;
118
+ cursor: pointer;
119
+
120
+ &:hover {
121
+ filter: brightness(1.3);
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ .visual_canvas {
128
+ position: relative;
129
+ width: 100%;
130
+ height: 100%;
131
+
132
+ i {
133
+ position: absolute;
134
+ top: 50%;
135
+ left: 50%;
136
+ transform: translate(-50%, -50%);
137
+ font-size: px2vw(100);
138
+ color: #fff;
139
+ opacity: 0.5;
140
+ }
141
+ }
142
+ }
28
143
  </style>
@@ -63,7 +63,6 @@ export default defineConfig({
63
63
  rollupOptions: {
64
64
  output: {
65
65
  manualChunks: {
66
- '@jnrs/core': ['@jnrs/core'],
67
66
  '@jnrs/shared': ['@jnrs/shared']
68
67
  }
69
68
  }
@@ -1,9 +1,21 @@
1
+ import type { IncomingMessage, ServerResponse } from 'http'
2
+
1
3
  const res_fail = {
2
4
  code: 1,
3
5
  msg: '操作失败'
4
6
  }
5
7
 
6
8
  export default [
9
+ // 404
10
+ {
11
+ url: '/mock/notFound',
12
+ method: 'get',
13
+ rawResponse: async (req: IncomingMessage, res: ServerResponse) => {
14
+ res.statusCode = 404
15
+ res.end('File not found')
16
+ return
17
+ }
18
+ },
7
19
  // 权限不足
8
20
  {
9
21
  url: '/mock/auth/no',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-jnrs-template-vue",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "巨能前端工程化开发,Vue 项目模板脚手架",
5
5
  "keywords": [
6
6
  "vue",