Showing
19 changed files
with
1257 additions
and
285 deletions
src/api/oem/index.ts
0 → 100644
1 | +import { defHttp } from '/@/utils/http/axios'; | ||
2 | +import { FileUploadResponse } from './model/index'; | ||
3 | +enum API { | ||
4 | + SELECT_DETAIL = '/enterprise/get', | ||
5 | + UPDATE_DETAIL = '/enterprise/update', | ||
6 | + TOWN_LIST = '/town/list', | ||
7 | + TOWN_CHILDS = '/town/childs', | ||
8 | + BaseUploadUrl = '/oss/upload', | ||
9 | + SELECT_PLATFORM = '/platform/get', | ||
10 | + UPDATE_PLATFORM = '/platform/update', | ||
11 | + | ||
12 | + SELECT_APP_DESIGN = '/appDesign/get', | ||
13 | + UPDATE_APP_DESIGN = '/appDesign/update', | ||
14 | +} | ||
15 | + | ||
16 | +// 查询企业信息 | ||
17 | +export const getEnterPriseDetail = () => { | ||
18 | + return defHttp.get({ | ||
19 | + url: API.SELECT_DETAIL, | ||
20 | + }); | ||
21 | +}; | ||
22 | + | ||
23 | +// 更新企业信息 | ||
24 | +export const updateEnterPriseDetail = (data) => { | ||
25 | + return defHttp.put({ | ||
26 | + url: API.UPDATE_DETAIL, | ||
27 | + data, | ||
28 | + }); | ||
29 | +}; | ||
30 | + | ||
31 | +// 获取所有省份 | ||
32 | +export const getTownList = () => { | ||
33 | + return defHttp.get({ | ||
34 | + url: API.TOWN_LIST, | ||
35 | + }); | ||
36 | +}; | ||
37 | + | ||
38 | +// 获取省份下面的地址 | ||
39 | +export const getTownChild = (key, value) => { | ||
40 | + return defHttp.get({ | ||
41 | + url: API.TOWN_CHILDS + `/${key}/${value}`, | ||
42 | + params: { | ||
43 | + variable: key, | ||
44 | + value, | ||
45 | + }, | ||
46 | + }); | ||
47 | +}; | ||
48 | + | ||
49 | +// logo上传 | ||
50 | +export const logoUpload = (file) => { | ||
51 | + return defHttp.post<FileUploadResponse>({ url: API.BaseUploadUrl, params: file }); | ||
52 | +}; | ||
53 | + | ||
54 | +// icon上传 | ||
55 | +export const iconUpload = (file) => { | ||
56 | + return defHttp.post<FileUploadResponse>({ url: API.BaseUploadUrl, params: file }); | ||
57 | +}; | ||
58 | + | ||
59 | +// 背景图片上传 | ||
60 | +export const bgUpload = (file) => { | ||
61 | + return defHttp.post<FileUploadResponse>({ url: API.BaseUploadUrl, params: file }); | ||
62 | +}; | ||
63 | + | ||
64 | +// 获取平台定制详情 | ||
65 | +export const getPlatForm = () => { | ||
66 | + return defHttp.get({ | ||
67 | + url: API.SELECT_PLATFORM, | ||
68 | + }); | ||
69 | +}; | ||
70 | + | ||
71 | +// 更新平台定制 | ||
72 | +export const updatePlatForm = (data) => { | ||
73 | + return defHttp.put({ | ||
74 | + url: API.UPDATE_PLATFORM, | ||
75 | + data, | ||
76 | + }); | ||
77 | +}; | ||
78 | + | ||
79 | +// APP定制 | ||
80 | +export const getAppDesign = () => { | ||
81 | + return defHttp.get({ | ||
82 | + url: API.SELECT_APP_DESIGN, | ||
83 | + }); | ||
84 | +}; | ||
85 | + | ||
86 | +// 更新APP定制 | ||
87 | +export const updateAppDesign = (data) => { | ||
88 | + return defHttp.put({ | ||
89 | + url: API.UPDATE_APP_DESIGN, | ||
90 | + data, | ||
91 | + }); | ||
92 | +}; |
src/api/oem/model/index.ts
0 → 100644
@@ -196,8 +196,8 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) { | @@ -196,8 +196,8 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) { | ||
196 | export const defHttp = createAxios(); | 196 | export const defHttp = createAxios(); |
197 | 197 | ||
198 | // other api url | 198 | // other api url |
199 | -// export const otherHttp = createAxios({ | ||
200 | -// requestOptions: { | ||
201 | -// apiUrl: 'xxx', | ||
202 | -// }, | ||
203 | -// }); | 199 | +export const otherHttp = createAxios({ |
200 | + requestOptions: { | ||
201 | + apiUrl: 'xxx', | ||
202 | + }, | ||
203 | +}); |
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | <template v-for="(item, index) in growCardList" :key="item.title"> | 3 | <template v-for="(item, index) in growCardList" :key="item.title"> |
4 | <div | 4 | <div |
5 | class="growCardItem md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4" | 5 | class="growCardItem md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4" |
6 | - :class="[index + 1 < growCardList.length && '!md:mr-4']" | 6 | + :class="[index + 1 < 3 && '!md:mr-4']" |
7 | > | 7 | > |
8 | <div class="growCardItem-top"> | 8 | <div class="growCardItem-top"> |
9 | <img :src="item.imgUrl" style="width: 90px; height: 90px" /> | 9 | <img :src="item.imgUrl" style="width: 90px; height: 90px" /> |
@@ -13,23 +13,31 @@ | @@ -13,23 +13,31 @@ | ||
13 | <img src="../../../../assets/images/tip.png" style="width: 20px; height: 20px" /> | 13 | <img src="../../../../assets/images/tip.png" style="width: 20px; height: 20px" /> |
14 | </div> | 14 | </div> |
15 | <div class="ml-3">{{ item.title }}</div> | 15 | <div class="ml-3">{{ item.title }}</div> |
16 | - <div class="ml-3 mt-3 flex" v-if="item.offLine"> | 16 | + <div class="ml-1.5 mt-3 flex flex-nowrap" style="width: 240px" v-if="item.offLine"> |
17 | <div class="count"> | 17 | <div class="count"> |
18 | - <img src="../../../../assets/images/online.png" style="width: 10px; height: 10px" /> | 18 | + <img |
19 | + src="../../../../assets/images/online.png" | ||
20 | + style="width: 10px; height: 10px; margin-right: 4px" | ||
21 | + /> | ||
19 | 在线 {{ item.onLine }} | 22 | 在线 {{ item.onLine }} |
20 | </div> | 23 | </div> |
21 | <div class="count"> | 24 | <div class="count"> |
22 | - <img src="../../../../assets/images/offline.png" alt="" /> | 25 | + <img |
26 | + src="../../../../assets/images/offline.png" | ||
27 | + style="width: 10px; height: 10px; margin-right: 4px" | ||
28 | + /> | ||
23 | 离线 {{ item.offLine }} | 29 | 离线 {{ item.offLine }} |
24 | </div> | 30 | </div> |
25 | <div class="count"> | 31 | <div class="count"> |
26 | - <img src="../../../../assets/images/inactive.png" alt="" /> | 32 | + <img |
33 | + src="../../../../assets/images/inactive.png" | ||
34 | + style="width: 10px; height: 10px; margin-right: 4px" | ||
35 | + /> | ||
27 | 未激活 {{ item.inactive }} | 36 | 未激活 {{ item.inactive }} |
28 | </div> | 37 | </div> |
29 | </div> | 38 | </div> |
30 | </div> | 39 | </div> |
31 | </div> | 40 | </div> |
32 | - | ||
33 | <div class="growCardItem-bottom"> 今日新增 {{ item.newDay }}</div> | 41 | <div class="growCardItem-bottom"> 今日新增 {{ item.newDay }}</div> |
34 | </div> | 42 | </div> |
35 | </template> | 43 | </template> |
@@ -43,7 +51,7 @@ | @@ -43,7 +51,7 @@ | ||
43 | .growCardItem { | 51 | .growCardItem { |
44 | height: 179px; | 52 | height: 179px; |
45 | background-color: #fff; | 53 | background-color: #fff; |
46 | - color: 666; | 54 | + color: #666; |
47 | .growCardItem-top { | 55 | .growCardItem-top { |
48 | display: flex; | 56 | display: flex; |
49 | margin: 20px; | 57 | margin: 20px; |
@@ -17,15 +17,15 @@ | @@ -17,15 +17,15 @@ | ||
17 | <List item-layout="horizontal" :data-source="data"> | 17 | <List item-layout="horizontal" :data-source="data"> |
18 | <template #renderItem="{ item }"> | 18 | <template #renderItem="{ item }"> |
19 | <ListItem> | 19 | <ListItem> |
20 | - <ListItemMeta description="有新的告警数据需要处理,现在就去查看吧"> | 20 | + <ListItemMeta :description="item.description"> |
21 | <template #title> | 21 | <template #title> |
22 | <a href="https://www.antdv.com/">{{ item.title }}</a> | 22 | <a href="https://www.antdv.com/">{{ item.title }}</a> |
23 | </template> | 23 | </template> |
24 | <template #avatar> | 24 | <template #avatar> |
25 | - <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" /> | 25 | + <Avatar :src="item.avatar" /> |
26 | </template> | 26 | </template> |
27 | </ListItemMeta> | 27 | </ListItemMeta> |
28 | - <template #extra> 7小时前 </template> | 28 | + <template #extra> {{ item.date }} </template> |
29 | </ListItem> | 29 | </ListItem> |
30 | </template> | 30 | </template> |
31 | </List> | 31 | </List> |
@@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
34 | </Card> | 34 | </Card> |
35 | <Card hoverable title="联系我们" :bordered="false"> | 35 | <Card hoverable title="联系我们" :bordered="false"> |
36 | <template #cover> | 36 | <template #cover> |
37 | - <QrCode :value="qrCodeUrl" /> | 37 | + <QrCode :value="qrCodeUrl" class="flex justify-center" /> |
38 | </template> | 38 | </template> |
39 | <CardMeta> | 39 | <CardMeta> |
40 | <template #description> | 40 | <template #description> |
@@ -48,9 +48,9 @@ | @@ -48,9 +48,9 @@ | ||
48 | </template> | 48 | </template> |
49 | 49 | ||
50 | <script lang="ts"> | 50 | <script lang="ts"> |
51 | - import { defineComponent, ref, unref } from 'vue'; | 51 | + import { defineComponent, ref } from 'vue'; |
52 | import { Card, AnchorLink, List, ListItem, ListItemMeta, Avatar, CardMeta } from 'ant-design-vue'; | 52 | import { Card, AnchorLink, List, ListItem, ListItemMeta, Avatar, CardMeta } from 'ant-design-vue'; |
53 | - import { QrCode, QrCodeActionType } from '/@/components/Qrcode/index'; | 53 | + import { QrCode } from '/@/components/Qrcode/index'; |
54 | export default defineComponent({ | 54 | export default defineComponent({ |
55 | components: { | 55 | components: { |
56 | Card, | 56 | Card, |
@@ -100,32 +100,44 @@ | @@ -100,32 +100,44 @@ | ||
100 | // 列表 | 100 | // 列表 |
101 | interface DataItem { | 101 | interface DataItem { |
102 | title: string; | 102 | title: string; |
103 | + description: string; | ||
104 | + avatar: string; | ||
105 | + date: string; | ||
103 | } | 106 | } |
104 | const data: DataItem[] = [ | 107 | const data: DataItem[] = [ |
105 | { | 108 | { |
106 | title: '企业管理员', | 109 | title: '企业管理员', |
110 | + description: '现在就来开创新的记录吧!', | ||
111 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | ||
112 | + date: '5分钟前', | ||
107 | }, | 113 | }, |
108 | { | 114 | { |
109 | title: '企业管理员', | 115 | title: '企业管理员', |
116 | + description: '有新的告警数据需要处理,现在去查看吧', | ||
117 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | ||
118 | + date: '7小时前', | ||
110 | }, | 119 | }, |
111 | { | 120 | { |
112 | title: '管理员', | 121 | title: '管理员', |
122 | + description: '有新的告警数据需要处理,现在去查看吧', | ||
123 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | ||
124 | + date: '6小时前', | ||
113 | }, | 125 | }, |
114 | { | 126 | { |
115 | title: '管理员', | 127 | title: '管理员', |
128 | + description: '现在就来开创新的记录吧!', | ||
129 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | ||
130 | + date: '1小时前', | ||
116 | }, | 131 | }, |
117 | { | 132 | { |
118 | title: '管理员', | 133 | title: '管理员', |
134 | + description: '现在就来开创新的记录吧!', | ||
135 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | ||
136 | + date: '7小时前', | ||
119 | }, | 137 | }, |
120 | ]; | 138 | ]; |
121 | 139 | ||
122 | - const qrRef = ref<Nullable<QrCodeActionType>>(null); | ||
123 | const qrCodeUrl = 'https://www.vvbin.cn'; | 140 | const qrCodeUrl = 'https://www.vvbin.cn'; |
124 | - const download = () => { | ||
125 | - const qrEl = unref(qrRef); | ||
126 | - if (!qrEl) return; | ||
127 | - qrEl.download('文件名'); | ||
128 | - }; | ||
129 | 141 | ||
130 | return { | 142 | return { |
131 | activeKey, | 143 | activeKey, |
@@ -134,7 +146,6 @@ | @@ -134,7 +146,6 @@ | ||
134 | data, | 146 | data, |
135 | helpDoc, | 147 | helpDoc, |
136 | qrCodeUrl, | 148 | qrCodeUrl, |
137 | - download, | ||
138 | }; | 149 | }; |
139 | }, | 150 | }, |
140 | }); | 151 | }); |
src/views/dashboard/analysis/components/SalesProductPie.vue
deleted
100644 → 0
1 | -<template> | ||
2 | - <Card title="成交占比" :loading="loading"> | ||
3 | - <div ref="chartRef" :style="{ width, height }"></div> | ||
4 | - </Card> | ||
5 | -</template> | ||
6 | -<script lang="ts" setup> | ||
7 | - import { Ref, ref, watch } from 'vue'; | ||
8 | - import { Card } from 'ant-design-vue'; | ||
9 | - import { useECharts } from '/@/hooks/web/useECharts'; | ||
10 | - | ||
11 | - const props = defineProps({ | ||
12 | - loading: Boolean, | ||
13 | - width: { | ||
14 | - type: String as PropType<string>, | ||
15 | - default: '100%', | ||
16 | - }, | ||
17 | - height: { | ||
18 | - type: String as PropType<string>, | ||
19 | - default: '300px', | ||
20 | - }, | ||
21 | - }); | ||
22 | - | ||
23 | - const chartRef = ref<HTMLDivElement | null>(null); | ||
24 | - const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | ||
25 | - watch( | ||
26 | - () => props.loading, | ||
27 | - () => { | ||
28 | - if (props.loading) { | ||
29 | - return; | ||
30 | - } | ||
31 | - setOptions({ | ||
32 | - tooltip: { | ||
33 | - trigger: 'item', | ||
34 | - }, | ||
35 | - | ||
36 | - series: [ | ||
37 | - { | ||
38 | - name: '访问来源', | ||
39 | - type: 'pie', | ||
40 | - radius: '80%', | ||
41 | - center: ['50%', '50%'], | ||
42 | - color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'], | ||
43 | - data: [ | ||
44 | - { value: 500, name: '电子产品' }, | ||
45 | - { value: 310, name: '服装' }, | ||
46 | - { value: 274, name: '化妆品' }, | ||
47 | - { value: 400, name: '家居' }, | ||
48 | - ].sort(function (a, b) { | ||
49 | - return a.value - b.value; | ||
50 | - }), | ||
51 | - roseType: 'radius', | ||
52 | - animationType: 'scale', | ||
53 | - animationEasing: 'exponentialInOut', | ||
54 | - animationDelay: function () { | ||
55 | - return Math.random() * 400; | ||
56 | - }, | ||
57 | - }, | ||
58 | - ], | ||
59 | - }); | ||
60 | - }, | ||
61 | - { immediate: true } | ||
62 | - ); | ||
63 | -</script> |
@@ -5,13 +5,29 @@ | @@ -5,13 +5,29 @@ | ||
5 | :active-tab-key="activeKey" | 5 | :active-tab-key="activeKey" |
6 | @tabChange="onTabChange" | 6 | @tabChange="onTabChange" |
7 | > | 7 | > |
8 | - <VisitAnalysis v-if="activeKey === 'tab1'" /> | ||
9 | - <VisitAnalysisBar v-else /> | 8 | + <template #tabBarExtraContent> |
9 | + <div class="extra-date"> | ||
10 | + <template v-for="(item, index) in dateList" :key="item"> | ||
11 | + <span @click="changeDate(index)" :class="{ active: index === activeIndex }">{{ | ||
12 | + item | ||
13 | + }}</span> | ||
14 | + </template> | ||
15 | + <DatePicker @change="onDateChange" /> | ||
16 | + </div> | ||
17 | + </template> | ||
18 | + <div v-if="activeKey === 'tab1'"> | ||
19 | + <p class="center">告警数</p> | ||
20 | + <VisitAnalysis /> | ||
21 | + </div> | ||
22 | + <div v-else> | ||
23 | + <p class="center">消息数</p> | ||
24 | + <VisitAnalysisBar /> | ||
25 | + </div> | ||
10 | </Card> | 26 | </Card> |
11 | </template> | 27 | </template> |
12 | <script lang="ts" setup> | 28 | <script lang="ts" setup> |
13 | import { ref } from 'vue'; | 29 | import { ref } from 'vue'; |
14 | - import { Card } from 'ant-design-vue'; | 30 | + import { Card, DatePicker } from 'ant-design-vue'; |
15 | import VisitAnalysis from './VisitAnalysis.vue'; | 31 | import VisitAnalysis from './VisitAnalysis.vue'; |
16 | import VisitAnalysisBar from './VisitAnalysisBar.vue'; | 32 | import VisitAnalysisBar from './VisitAnalysisBar.vue'; |
17 | 33 | ||
@@ -27,8 +43,36 @@ | @@ -27,8 +43,36 @@ | ||
27 | tab: '消息量统计', | 43 | tab: '消息量统计', |
28 | }, | 44 | }, |
29 | ]; | 45 | ]; |
30 | - | 46 | + const dateList = ref(['1小时', '1天', '7天', '30天']); |
47 | + const activeIndex = ref(0); | ||
31 | function onTabChange(key) { | 48 | function onTabChange(key) { |
32 | activeKey.value = key; | 49 | activeKey.value = key; |
33 | } | 50 | } |
51 | + function onDateChange(date, dateString) { | ||
52 | + console.log(date, dateString); | ||
53 | + } | ||
54 | + function changeDate(index: number) { | ||
55 | + activeIndex.value = index; | ||
56 | + } | ||
34 | </script> | 57 | </script> |
58 | + | ||
59 | +<style scoped lang="less"> | ||
60 | + .center { | ||
61 | + display: flex; | ||
62 | + justify-content: center; | ||
63 | + font-size: 16px; | ||
64 | + } | ||
65 | + .active { | ||
66 | + color: #0960bd; | ||
67 | + font-weight: 500; | ||
68 | + } | ||
69 | + .extra-date { | ||
70 | + display: flex; | ||
71 | + align-items: center; | ||
72 | + justify-content: space-between; | ||
73 | + span { | ||
74 | + margin-right: 20px; | ||
75 | + cursor: pointer; | ||
76 | + } | ||
77 | + } | ||
78 | +</style> |
@@ -88,18 +88,6 @@ | @@ -88,18 +88,6 @@ | ||
88 | color: '#5ab1ef', | 88 | color: '#5ab1ef', |
89 | }, | 89 | }, |
90 | }, | 90 | }, |
91 | - { | ||
92 | - smooth: true, | ||
93 | - data: [ | ||
94 | - 33, 66, 88, 333, 3333, 5000, 18000, 3000, 1200, 13000, 22000, 11000, 2221, 1201, 390, | ||
95 | - 198, 60, 30, 22, 11, | ||
96 | - ], | ||
97 | - type: 'line', | ||
98 | - areaStyle: {}, | ||
99 | - itemStyle: { | ||
100 | - color: '#019680', | ||
101 | - }, | ||
102 | - }, | ||
103 | ], | 91 | ], |
104 | }); | 92 | }); |
105 | }); | 93 | }); |
src/views/dashboard/analysis/components/VisitRadar.vue
deleted
100644 → 0
1 | -<template> | ||
2 | - <Card title="转化率" :loading="loading"> | ||
3 | - <div ref="chartRef" :style="{ width, height }"></div> | ||
4 | - </Card> | ||
5 | -</template> | ||
6 | -<script lang="ts" setup> | ||
7 | - import { Ref, ref, watch } from 'vue'; | ||
8 | - import { Card } from 'ant-design-vue'; | ||
9 | - import { useECharts } from '/@/hooks/web/useECharts'; | ||
10 | - | ||
11 | - const props = defineProps({ | ||
12 | - loading: Boolean, | ||
13 | - width: { | ||
14 | - type: String as PropType<string>, | ||
15 | - default: '100%', | ||
16 | - }, | ||
17 | - height: { | ||
18 | - type: String as PropType<string>, | ||
19 | - default: '300px', | ||
20 | - }, | ||
21 | - }); | ||
22 | - | ||
23 | - const chartRef = ref<HTMLDivElement | null>(null); | ||
24 | - const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | ||
25 | - watch( | ||
26 | - () => props.loading, | ||
27 | - () => { | ||
28 | - if (props.loading) { | ||
29 | - return; | ||
30 | - } | ||
31 | - setOptions({ | ||
32 | - legend: { | ||
33 | - bottom: 0, | ||
34 | - data: ['访问', '购买'], | ||
35 | - }, | ||
36 | - tooltip: {}, | ||
37 | - radar: { | ||
38 | - radius: '60%', | ||
39 | - splitNumber: 8, | ||
40 | - indicator: [ | ||
41 | - { | ||
42 | - text: '电脑', | ||
43 | - max: 100, | ||
44 | - }, | ||
45 | - { | ||
46 | - text: '充电器', | ||
47 | - max: 100, | ||
48 | - }, | ||
49 | - { | ||
50 | - text: '耳机', | ||
51 | - max: 100, | ||
52 | - }, | ||
53 | - { | ||
54 | - text: '手机', | ||
55 | - max: 100, | ||
56 | - }, | ||
57 | - { | ||
58 | - text: 'Ipad', | ||
59 | - max: 100, | ||
60 | - }, | ||
61 | - { | ||
62 | - text: '耳机', | ||
63 | - max: 100, | ||
64 | - }, | ||
65 | - ], | ||
66 | - }, | ||
67 | - series: [ | ||
68 | - { | ||
69 | - type: 'radar', | ||
70 | - symbolSize: 0, | ||
71 | - areaStyle: { | ||
72 | - shadowBlur: 0, | ||
73 | - shadowColor: 'rgba(0,0,0,.2)', | ||
74 | - shadowOffsetX: 0, | ||
75 | - shadowOffsetY: 10, | ||
76 | - opacity: 1, | ||
77 | - }, | ||
78 | - data: [ | ||
79 | - { | ||
80 | - value: [90, 50, 86, 40, 50, 20], | ||
81 | - name: '访问', | ||
82 | - itemStyle: { | ||
83 | - color: '#b6a2de', | ||
84 | - }, | ||
85 | - }, | ||
86 | - { | ||
87 | - value: [70, 75, 70, 76, 20, 85], | ||
88 | - name: '购买', | ||
89 | - itemStyle: { | ||
90 | - color: '#5ab1ef', | ||
91 | - }, | ||
92 | - }, | ||
93 | - ], | ||
94 | - }, | ||
95 | - ], | ||
96 | - }); | ||
97 | - }, | ||
98 | - { immediate: true } | ||
99 | - ); | ||
100 | -</script> |
src/views/dashboard/analysis/components/VisitSource.vue
deleted
100644 → 0
1 | -<template> | ||
2 | - <Card title="访问来源" :loading="loading"> | ||
3 | - <div ref="chartRef" :style="{ width, height }"></div> | ||
4 | - </Card> | ||
5 | -</template> | ||
6 | -<script lang="ts" setup> | ||
7 | - import { Ref, ref, watch } from 'vue'; | ||
8 | - import { Card } from 'ant-design-vue'; | ||
9 | - import { useECharts } from '/@/hooks/web/useECharts'; | ||
10 | - const props = defineProps({ | ||
11 | - loading: Boolean, | ||
12 | - width: { | ||
13 | - type: String as PropType<string>, | ||
14 | - default: '100%', | ||
15 | - }, | ||
16 | - height: { | ||
17 | - type: String as PropType<string>, | ||
18 | - default: '300px', | ||
19 | - }, | ||
20 | - }); | ||
21 | - const chartRef = ref<HTMLDivElement | null>(null); | ||
22 | - const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>); | ||
23 | - watch( | ||
24 | - () => props.loading, | ||
25 | - () => { | ||
26 | - if (props.loading) { | ||
27 | - return; | ||
28 | - } | ||
29 | - setOptions({ | ||
30 | - tooltip: { | ||
31 | - trigger: 'item', | ||
32 | - }, | ||
33 | - legend: { | ||
34 | - bottom: '1%', | ||
35 | - left: 'center', | ||
36 | - }, | ||
37 | - series: [ | ||
38 | - { | ||
39 | - color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'], | ||
40 | - name: '访问来源', | ||
41 | - type: 'pie', | ||
42 | - radius: ['40%', '70%'], | ||
43 | - avoidLabelOverlap: false, | ||
44 | - itemStyle: { | ||
45 | - borderRadius: 10, | ||
46 | - borderColor: '#fff', | ||
47 | - borderWidth: 2, | ||
48 | - }, | ||
49 | - label: { | ||
50 | - show: false, | ||
51 | - position: 'center', | ||
52 | - }, | ||
53 | - emphasis: { | ||
54 | - label: { | ||
55 | - show: true, | ||
56 | - fontSize: '12', | ||
57 | - fontWeight: 'bold', | ||
58 | - }, | ||
59 | - }, | ||
60 | - labelLine: { | ||
61 | - show: false, | ||
62 | - }, | ||
63 | - data: [ | ||
64 | - { value: 1048, name: '搜索引擎' }, | ||
65 | - { value: 735, name: '直接访问' }, | ||
66 | - { value: 580, name: '邮件营销' }, | ||
67 | - { value: 484, name: '联盟广告' }, | ||
68 | - ], | ||
69 | - animationType: 'scale', | ||
70 | - animationEasing: 'exponentialInOut', | ||
71 | - animationDelay: function () { | ||
72 | - return Math.random() * 100; | ||
73 | - }, | ||
74 | - }, | ||
75 | - ], | ||
76 | - }); | ||
77 | - }, | ||
78 | - { immediate: true } | ||
79 | - ); | ||
80 | -</script> |
@@ -12,7 +12,7 @@ export const growCardList: GrowCardItem[] = [ | @@ -12,7 +12,7 @@ export const growCardList: GrowCardItem[] = [ | ||
12 | { | 12 | { |
13 | imgUrl: '/src/assets/images/device-count.png', | 13 | imgUrl: '/src/assets/images/device-count.png', |
14 | title: '设备数(个)', | 14 | title: '设备数(个)', |
15 | - value: '10,0000', | 15 | + value: '10,000', |
16 | onLine: 2000, | 16 | onLine: 2000, |
17 | offLine: 3000, | 17 | offLine: 3000, |
18 | inactive: 4000, | 18 | inactive: 4000, |
1 | +<template> | ||
2 | + <div class="card"> | ||
3 | + <Card :bordered="false" class="card"> | ||
4 | + <BasicForm @register="registerForm"> | ||
5 | + <template #logoUpload> | ||
6 | + <Upload | ||
7 | + name="avatar" | ||
8 | + list-type="picture-card" | ||
9 | + class="avatar-uploader" | ||
10 | + :show-upload-list="false" | ||
11 | + @preview="handlePreview" | ||
12 | + :customRequest="customUploadLogoPic" | ||
13 | + :before-upload="beforeUploadLogoPic" | ||
14 | + > | ||
15 | + <img v-if="logoPic" :src="logoPic" /> | ||
16 | + <div v-else> | ||
17 | + <div style="margin-top: 30px"> | ||
18 | + <PlusOutlined style="font-size: 30px" /> | ||
19 | + </div> | ||
20 | + <div | ||
21 | + class="ant-upload-text flex" | ||
22 | + style="width: 180px; height: 130px; align-items: center" | ||
23 | + > | ||
24 | + 支持.PNG、.JPG、.SVG格式,建议尺寸32px × 32px,大小不超过500KB。</div | ||
25 | + > | ||
26 | + </div> | ||
27 | + </Upload> | ||
28 | + </template> | ||
29 | + <template #bgUpload> | ||
30 | + <Upload | ||
31 | + name="avatar" | ||
32 | + list-type="picture-card" | ||
33 | + class="avatar-uploader" | ||
34 | + :show-upload-list="false" | ||
35 | + :customRequest="customUploadBgPic" | ||
36 | + :before-upload="beforeUploadBgPic" | ||
37 | + > | ||
38 | + <img v-if="bgPic" :src="bgPic" alt="avatar" /> | ||
39 | + <div v-else> | ||
40 | + <div style="margin-top: 30px"> | ||
41 | + <PlusOutlined style="font-size: 30px" /> | ||
42 | + </div> | ||
43 | + <div | ||
44 | + class="ant-upload-text flex" | ||
45 | + style="width: 280px; height: 130px; align-items: center" | ||
46 | + > | ||
47 | + 支持.PNG、.JPG、.SVG格式,建议尺寸为1250px × 730px(及以上),大小不超过5M。</div | ||
48 | + > | ||
49 | + </div> | ||
50 | + </Upload> | ||
51 | + </template> | ||
52 | + <template #colorInput="{ model, field }" | ||
53 | + ><Input disabled v-model:value="model[field]"> | ||
54 | + <template #prefix> <input type="color" v-model="model[field]" /> </template | ||
55 | + ></Input> | ||
56 | + </template> | ||
57 | + | ||
58 | + <template #homeSwiper> | ||
59 | + <Upload | ||
60 | + v-model:file-list="fileList" | ||
61 | + list-type="picture-card" | ||
62 | + @preview="handlePreview" | ||
63 | + :customRequest="customUploadHomeSwiper" | ||
64 | + :before-upload="beforeUploadHomeSwiper" | ||
65 | + > | ||
66 | + <div v-if="fileList.length < 5"> | ||
67 | + <plus-outlined /> | ||
68 | + <div class="ant-upload-text">Upload</div> | ||
69 | + </div> | ||
70 | + </Upload> | ||
71 | + <Modal :visible="previewVisible" :footer="null" @cancel="handleCancel"> | ||
72 | + <img alt="example" style="width: 100%" :src="previewImage" /> | ||
73 | + </Modal> | ||
74 | + </template> | ||
75 | + </BasicForm> | ||
76 | + </Card> | ||
77 | + <Loading v-bind="compState" /> | ||
78 | + <a-button | ||
79 | + @click="handleUpdateInfo" | ||
80 | + size="large" | ||
81 | + type="primary" | ||
82 | + style="margin-top: 20px; background-color: #2950f7; border-radius: 5px" | ||
83 | + >保存信息</a-button | ||
84 | + > | ||
85 | + </div> | ||
86 | +</template> | ||
87 | + | ||
88 | +<script lang="ts"> | ||
89 | + import { defineComponent, ref, unref, onMounted } from 'vue'; | ||
90 | + import { BasicForm, useForm } from '/@/components/Form/index'; | ||
91 | + import { Loading } from '/@/components/Loading/index'; | ||
92 | + import { Card, Upload, Input, Modal } from 'ant-design-vue'; | ||
93 | + import { PlusOutlined } from '@ant-design/icons-vue'; | ||
94 | + import { schemas } from '../config/AppDraw.config'; | ||
95 | + import { FileItem, FileInfo } from '../types/index'; | ||
96 | + import { logoUpload, bgUpload } from '/@/api/oem/index'; | ||
97 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
98 | + import { getAppDesign, updateAppDesign } from '/@/api/oem/index'; | ||
99 | + export default defineComponent({ | ||
100 | + components: { | ||
101 | + Card, | ||
102 | + BasicForm, | ||
103 | + Upload, | ||
104 | + Loading, | ||
105 | + PlusOutlined, | ||
106 | + Input, | ||
107 | + Modal, | ||
108 | + }, | ||
109 | + setup() { | ||
110 | + const compState = ref({ | ||
111 | + absolute: false, | ||
112 | + loading: false, | ||
113 | + tip: '拼命加载中...', | ||
114 | + }); | ||
115 | + const { createMessage } = useMessage(); | ||
116 | + const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({ | ||
117 | + schemas, | ||
118 | + showSubmitButton: false, | ||
119 | + showResetButton: false, | ||
120 | + labelWidth: 150, | ||
121 | + wrapperCol: { | ||
122 | + span: 10, | ||
123 | + }, | ||
124 | + }); | ||
125 | + const previewVisible = ref<boolean>(false); | ||
126 | + const previewImage = ref<string | undefined>(''); | ||
127 | + function getBase64(file: File) { | ||
128 | + return new Promise((resolve, reject) => { | ||
129 | + const reader = new FileReader(); | ||
130 | + reader.readAsDataURL(file); | ||
131 | + reader.onload = () => resolve(reader.result); | ||
132 | + reader.onerror = (error) => reject(error); | ||
133 | + }); | ||
134 | + } | ||
135 | + const handleCancel = () => { | ||
136 | + previewVisible.value = false; | ||
137 | + }; | ||
138 | + const handlePreview = async (file: FileItem) => { | ||
139 | + console.log(file); | ||
140 | + if (!file.url && !file.preview) { | ||
141 | + file.preview = (await getBase64(file.originFileObj)) as string; | ||
142 | + } | ||
143 | + previewImage.value = file.url || file.preview; | ||
144 | + previewVisible.value = true; | ||
145 | + }; | ||
146 | + const handleChange = ({ fileList: newFileList }: FileInfo) => { | ||
147 | + fileList.value = newFileList; | ||
148 | + }; | ||
149 | + | ||
150 | + // logo图片上传 | ||
151 | + const logoPic = ref(); | ||
152 | + async function customUploadLogoPic({ file }) { | ||
153 | + if (beforeUploadLogoPic(file)) { | ||
154 | + const formData = new FormData(); | ||
155 | + formData.append('file', file); | ||
156 | + const response = await logoUpload(formData); | ||
157 | + if (response.fileStaticUri) { | ||
158 | + logoPic.value = response.fileStaticUri; | ||
159 | + } | ||
160 | + } | ||
161 | + } | ||
162 | + const beforeUploadLogoPic = (file) => { | ||
163 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | ||
164 | + if (!isJpgOrPng) { | ||
165 | + createMessage.error('只能上传图片文件!'); | ||
166 | + } | ||
167 | + const isLt2M = (file.size as number) / 1024 < 500; | ||
168 | + if (!isLt2M) { | ||
169 | + createMessage.error('图片大小不能超过500KB!'); | ||
170 | + } | ||
171 | + return isJpgOrPng && isLt2M; | ||
172 | + }; | ||
173 | + | ||
174 | + // 登录页背景上传 | ||
175 | + const bgPic = ref(); | ||
176 | + async function customUploadBgPic({ file }) { | ||
177 | + if (beforeUploadBgPic(file)) { | ||
178 | + const formData = new FormData(); | ||
179 | + formData.append('file', file); | ||
180 | + const response = await bgUpload(formData); | ||
181 | + if (response.fileStaticUri) { | ||
182 | + bgPic.value = response.fileStaticUri; | ||
183 | + } | ||
184 | + } | ||
185 | + } | ||
186 | + const beforeUploadBgPic = (file) => { | ||
187 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | ||
188 | + if (!isJpgOrPng) { | ||
189 | + createMessage.error('只能上传图片文件!'); | ||
190 | + } | ||
191 | + const isLt2M = (file.size as number) / 1024 / 1024 < 5; | ||
192 | + if (!isLt2M) { | ||
193 | + createMessage.error('图片大小不能超过5MB!'); | ||
194 | + } | ||
195 | + return isJpgOrPng && isLt2M; | ||
196 | + }; | ||
197 | + // 首页轮播图 | ||
198 | + const fileList = ref<FileItem[]>([]); | ||
199 | + async function customUploadHomeSwiper({ file }) { | ||
200 | + if (beforeUploadHomeSwiper(file)) { | ||
201 | + const formData = new FormData(); | ||
202 | + formData.append('file', file); | ||
203 | + | ||
204 | + const response = await bgUpload(formData); | ||
205 | + if (response.fileStaticUri) { | ||
206 | + fileList.value.push({ | ||
207 | + uid: -Math.random() + '', | ||
208 | + name: response.fileName, | ||
209 | + status: 'done', | ||
210 | + url: response.fileStaticUri, | ||
211 | + }); | ||
212 | + console.log('改变前', fileList.value); | ||
213 | + const fileArr = fileList.value.filter((item) => { | ||
214 | + return item.percent !== 0; | ||
215 | + }); | ||
216 | + fileList.value = fileArr; | ||
217 | + } | ||
218 | + } | ||
219 | + } | ||
220 | + | ||
221 | + const beforeUploadHomeSwiper = (file) => { | ||
222 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | ||
223 | + if (!isJpgOrPng) { | ||
224 | + createMessage.error('只能上传图片文件!'); | ||
225 | + } | ||
226 | + const isLt2M = (file.size as number) / 1024 / 1024 < 5; | ||
227 | + if (!isLt2M) { | ||
228 | + createMessage.error('图片大小不能超过5MB!'); | ||
229 | + } | ||
230 | + return isJpgOrPng && isLt2M; | ||
231 | + }; | ||
232 | + | ||
233 | + const handleUpdateInfo = async () => { | ||
234 | + try { | ||
235 | + console.log(fileList.value); | ||
236 | + const fieldValue = getFieldsValue(); | ||
237 | + // 做换字段 | ||
238 | + const homeSwiper = fileList.value.map((item) => item.url); | ||
239 | + const rotation = homeSwiper.join(','); | ||
240 | + | ||
241 | + compState.value.loading = true; | ||
242 | + await updateAppDesign({ | ||
243 | + ...fieldValue, | ||
244 | + background: unref(bgPic), | ||
245 | + icon: unref(bgPic), | ||
246 | + logo: unref(logoPic), | ||
247 | + rotation, | ||
248 | + }); | ||
249 | + compState.value.loading = false; | ||
250 | + createMessage.success('保存信息成功'); | ||
251 | + } catch (e) { | ||
252 | + createMessage.error('保存信息失败'); | ||
253 | + } | ||
254 | + }; | ||
255 | + | ||
256 | + onMounted(async () => { | ||
257 | + const res = await getAppDesign(); | ||
258 | + const rotation = res.rotation.split(','); | ||
259 | + const arr: any[] = []; | ||
260 | + for (let item of rotation) { | ||
261 | + arr.push({ | ||
262 | + uid: -Math.random() + '', | ||
263 | + name: '111', | ||
264 | + url: item, | ||
265 | + status: 'done', | ||
266 | + }); | ||
267 | + } | ||
268 | + setFieldsValue(res); | ||
269 | + logoPic.value = res.logo; | ||
270 | + bgPic.value = res.background; | ||
271 | + if (arr[0].url === '') return; | ||
272 | + fileList.value = arr; | ||
273 | + }); | ||
274 | + return { | ||
275 | + compState, | ||
276 | + fileList, | ||
277 | + registerForm, | ||
278 | + handleUpdateInfo, | ||
279 | + handleCancel, | ||
280 | + handlePreview, | ||
281 | + customUploadLogoPic, | ||
282 | + beforeUploadLogoPic, | ||
283 | + customUploadBgPic, | ||
284 | + beforeUploadBgPic, | ||
285 | + customUploadHomeSwiper, | ||
286 | + beforeUploadHomeSwiper, | ||
287 | + handleChange, | ||
288 | + logoPic, | ||
289 | + bgPic, | ||
290 | + previewVisible, | ||
291 | + previewImage, | ||
292 | + }; | ||
293 | + }, | ||
294 | + }); | ||
295 | +</script> | ||
296 | + | ||
297 | +<style lang="less" scoped> | ||
298 | + .ant-upload-select-picture-card i { | ||
299 | + font-size: 32px; | ||
300 | + color: #999; | ||
301 | + } | ||
302 | + | ||
303 | + .ant-upload-select-picture-card .ant-upload-text { | ||
304 | + margin-top: 8px; | ||
305 | + color: #666; | ||
306 | + } | ||
307 | +</style> |
1 | +<template> | ||
2 | + <div class="card"> | ||
3 | + <Card :bordered="false" class="card"> | ||
4 | + <BasicForm @register="registerForm"> | ||
5 | + <template #logoUpload> | ||
6 | + <Upload | ||
7 | + name="avatar" | ||
8 | + list-type="picture-card" | ||
9 | + class="avatar-uploader" | ||
10 | + :show-upload-list="false" | ||
11 | + :customRequest="customUploadLogoPic" | ||
12 | + :before-upload="beforeUploadLogoPic" | ||
13 | + > | ||
14 | + <img v-if="logoPic" :src="logoPic" /> | ||
15 | + <div v-else> | ||
16 | + <div style="margin-top: 30px"> | ||
17 | + <PlusOutlined style="font-size: 30px" /> | ||
18 | + </div> | ||
19 | + <div | ||
20 | + class="ant-upload-text flex" | ||
21 | + style="width: 180px; height: 130px; align-items: center" | ||
22 | + > | ||
23 | + 支持.PNG、.JPG、.SVG格式,建议尺寸32px × 32px,大小不超过500KB。</div | ||
24 | + > | ||
25 | + </div> | ||
26 | + </Upload> | ||
27 | + </template> | ||
28 | + <template #iconUpload> | ||
29 | + <Upload | ||
30 | + name="avatar" | ||
31 | + list-type="picture-card" | ||
32 | + class="avatar-uploader" | ||
33 | + :show-upload-list="false" | ||
34 | + :customRequest="customUploadIconPic" | ||
35 | + :before-upload="beforeUploadIconPic" | ||
36 | + > | ||
37 | + <div v-if="iconPic"> | ||
38 | + <img :src="iconPic" /> | ||
39 | + <div style="background-color: #ccc">重新上传</div> | ||
40 | + </div> | ||
41 | + <div v-else> | ||
42 | + <PlusOutlined style="font-size: 30px" /> | ||
43 | + </div> | ||
44 | + </Upload> | ||
45 | + </template> | ||
46 | + <template #bgUpload> | ||
47 | + <Upload | ||
48 | + name="avatar" | ||
49 | + list-type="picture-card" | ||
50 | + class="avatar-uploader" | ||
51 | + :show-upload-list="false" | ||
52 | + :customRequest="customUploadBgPic" | ||
53 | + :before-upload="beforeUploadBgPic" | ||
54 | + > | ||
55 | + <img v-if="bgPic" :src="bgPic" alt="avatar" /> | ||
56 | + <div v-else> | ||
57 | + <div style="margin-top: 30px"> | ||
58 | + <PlusOutlined style="font-size: 30px" /> | ||
59 | + </div> | ||
60 | + <div | ||
61 | + class="ant-upload-text flex" | ||
62 | + style="width: 280px; height: 130px; align-items: center" | ||
63 | + > | ||
64 | + 支持.PNG、.JPG、.SVG格式,建议尺寸为1250px × 730px(及以上),大小不超过5M。</div | ||
65 | + > | ||
66 | + </div> | ||
67 | + </Upload> | ||
68 | + </template> | ||
69 | + | ||
70 | + <template #colorInput="{ model, field }" | ||
71 | + ><Input disabled v-model:value="model[field]"> | ||
72 | + <template #prefix> <input type="color" v-model="model[field]" /> </template | ||
73 | + ></Input> | ||
74 | + </template> | ||
75 | + </BasicForm> | ||
76 | + </Card> | ||
77 | + <Loading v-bind="compState" /> | ||
78 | + <a-button | ||
79 | + @click="handleUpdateInfo" | ||
80 | + size="large" | ||
81 | + type="primary" | ||
82 | + style="margin-top: 20px; background-color: #2950f7; border-radius: 5px" | ||
83 | + >保存信息</a-button | ||
84 | + > | ||
85 | + </div> | ||
86 | +</template> | ||
87 | + | ||
88 | +<script lang="ts"> | ||
89 | + import { defineComponent, ref, onMounted, unref } from 'vue'; | ||
90 | + import { Card, Upload, Input } from 'ant-design-vue'; | ||
91 | + import { BasicForm, useForm } from '/@/components/Form/index'; | ||
92 | + import { schemas } from '../config/CVIDraw.config'; | ||
93 | + import { Loading } from '/@/components/Loading/index'; | ||
94 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
95 | + import type { FileItem } from '/@/components/Upload/src/typing'; | ||
96 | + import { logoUpload, iconUpload, bgUpload, getPlatForm, updatePlatForm } from '/@/api/oem/index'; | ||
97 | + import { PlusOutlined } from '@ant-design/icons-vue'; | ||
98 | + export default defineComponent({ | ||
99 | + components: { | ||
100 | + BasicForm, | ||
101 | + Card, | ||
102 | + Loading, | ||
103 | + Upload, | ||
104 | + Input, | ||
105 | + PlusOutlined, | ||
106 | + }, | ||
107 | + setup() { | ||
108 | + const compState = ref({ | ||
109 | + absolute: false, | ||
110 | + loading: false, | ||
111 | + tip: '拼命加载中...', | ||
112 | + }); | ||
113 | + const { createMessage } = useMessage(); | ||
114 | + const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({ | ||
115 | + schemas, | ||
116 | + showSubmitButton: false, | ||
117 | + showResetButton: false, | ||
118 | + labelWidth: 150, | ||
119 | + wrapperCol: { | ||
120 | + span: 10, | ||
121 | + }, | ||
122 | + }); | ||
123 | + | ||
124 | + const logoPic = ref(); | ||
125 | + const iconPic = ref(); | ||
126 | + const bgPic = ref(); | ||
127 | + // logo图片上传 | ||
128 | + async function customUploadLogoPic({ file }) { | ||
129 | + if (beforeUploadLogoPic(file)) { | ||
130 | + const formData = new FormData(); | ||
131 | + formData.append('file', file); | ||
132 | + const response = await logoUpload(formData); | ||
133 | + if (response.fileStaticUri) { | ||
134 | + logoPic.value = response.fileStaticUri; | ||
135 | + } | ||
136 | + } | ||
137 | + } | ||
138 | + const beforeUploadLogoPic = (file: FileItem) => { | ||
139 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | ||
140 | + if (!isJpgOrPng) { | ||
141 | + createMessage.error('只能上传图片文件!'); | ||
142 | + } | ||
143 | + const isLt2M = (file.size as number) / 1024 < 500; | ||
144 | + if (!isLt2M) { | ||
145 | + createMessage.error('图片大小不能超过500KB!'); | ||
146 | + } | ||
147 | + return isJpgOrPng && isLt2M; | ||
148 | + }; | ||
149 | + | ||
150 | + async function customUploadIconPic({ file }) { | ||
151 | + if (beforeUploadIconPic(file)) { | ||
152 | + const formData = new FormData(); | ||
153 | + formData.append('file', file); | ||
154 | + const response = await iconUpload(formData); | ||
155 | + if (response.fileStaticUri) { | ||
156 | + iconPic.value = response.fileStaticUri; | ||
157 | + } | ||
158 | + } | ||
159 | + } | ||
160 | + const beforeUploadIconPic = (file: FileItem) => { | ||
161 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | ||
162 | + if (!isJpgOrPng) { | ||
163 | + createMessage.error('只能上传图片文件!'); | ||
164 | + } | ||
165 | + const isLt2M = (file.size as number) / 1024 < 500; | ||
166 | + if (!isLt2M) { | ||
167 | + createMessage.error('图片大小不能超过500KB!'); | ||
168 | + } | ||
169 | + return isJpgOrPng && isLt2M; | ||
170 | + }; | ||
171 | + // 登录页背景上传 | ||
172 | + async function customUploadBgPic({ file }) { | ||
173 | + if (beforeUploadBgPic(file)) { | ||
174 | + const formData = new FormData(); | ||
175 | + formData.append('file', file); | ||
176 | + const response = await bgUpload(formData); | ||
177 | + if (response.fileStaticUri) { | ||
178 | + bgPic.value = response.fileStaticUri; | ||
179 | + } | ||
180 | + } | ||
181 | + } | ||
182 | + const beforeUploadBgPic = (file: FileItem) => { | ||
183 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | ||
184 | + if (!isJpgOrPng) { | ||
185 | + createMessage.error('只能上传图片文件!'); | ||
186 | + } | ||
187 | + const isLt2M = (file.size as number) / 1024 / 1024 < 5; | ||
188 | + if (!isLt2M) { | ||
189 | + createMessage.error('图片大小不能超过5MB!'); | ||
190 | + } | ||
191 | + return isJpgOrPng && isLt2M; | ||
192 | + }; | ||
193 | + | ||
194 | + // 更新 | ||
195 | + const handleUpdateInfo = async () => { | ||
196 | + try { | ||
197 | + const fieldValue = getFieldsValue(); | ||
198 | + compState.value.loading = true; | ||
199 | + await updatePlatForm({ | ||
200 | + ...fieldValue, | ||
201 | + background: unref(bgPic), | ||
202 | + icon: unref(bgPic), | ||
203 | + logo: unref(logoPic), | ||
204 | + }); | ||
205 | + compState.value.loading = false; | ||
206 | + createMessage.success('保存信息成功'); | ||
207 | + } catch (e) { | ||
208 | + createMessage.error('保存信息失败'); | ||
209 | + } | ||
210 | + }; | ||
211 | + | ||
212 | + onMounted(async () => { | ||
213 | + const res = await getPlatForm(); | ||
214 | + setFieldsValue(res); | ||
215 | + logoPic.value = res.logo; | ||
216 | + iconPic.value = res.icon; | ||
217 | + bgPic.value = res.background; | ||
218 | + }); | ||
219 | + return { | ||
220 | + registerForm, | ||
221 | + logoPic, | ||
222 | + iconPic, | ||
223 | + bgPic, | ||
224 | + customUploadLogoPic, | ||
225 | + beforeUploadLogoPic, | ||
226 | + customUploadIconPic, | ||
227 | + beforeUploadIconPic, | ||
228 | + customUploadBgPic, | ||
229 | + beforeUploadBgPic, | ||
230 | + compState, | ||
231 | + handleUpdateInfo, | ||
232 | + }; | ||
233 | + }, | ||
234 | + }); | ||
235 | +</script> | ||
236 | + | ||
237 | +<style lang="less" scoped></style> |
1 | +<template> | ||
2 | + <div class="card"> | ||
3 | + <Card :bordered="false" class="card"> <BasicForm @register="registerForm" /></Card> | ||
4 | + <Loading v-bind="compState" /> | ||
5 | + <a-button | ||
6 | + @click="handleUpdateInfo" | ||
7 | + size="large" | ||
8 | + type="primary" | ||
9 | + style="margin-top: 20px; background-color: #2950f7; border-radius: 5px" | ||
10 | + >更新基本信息</a-button | ||
11 | + > | ||
12 | + </div> | ||
13 | +</template> | ||
14 | + | ||
15 | +<script lang="ts"> | ||
16 | + import { defineComponent, onMounted, ref } from 'vue'; | ||
17 | + import { Card } from 'ant-design-vue'; | ||
18 | + import { BasicForm, useForm } from '/@/components/Form/index'; | ||
19 | + import { schemas } from '../config/enterPriseInfo.config'; | ||
20 | + import { getEnterPriseDetail, updateEnterPriseDetail } from '/@/api/oem/index'; | ||
21 | + import { Loading } from '/@/components/Loading'; | ||
22 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
23 | + export default defineComponent({ | ||
24 | + components: { | ||
25 | + Card, | ||
26 | + BasicForm, | ||
27 | + Loading, | ||
28 | + }, | ||
29 | + setup() { | ||
30 | + const compState = ref({ | ||
31 | + absolute: false, | ||
32 | + loading: false, | ||
33 | + tip: '拼命加载中...', | ||
34 | + }); | ||
35 | + const [registerForm, { getFieldsValue, setFieldsValue }] = useForm({ | ||
36 | + labelWidth: 80, | ||
37 | + schemas, | ||
38 | + showResetButton: false, | ||
39 | + showSubmitButton: false, | ||
40 | + wrapperCol: { | ||
41 | + span: 10, | ||
42 | + }, | ||
43 | + }); | ||
44 | + const { createMessage } = useMessage(); | ||
45 | + const handleUpdateInfo = async () => { | ||
46 | + try { | ||
47 | + compState.value.loading = true; | ||
48 | + const fieldsValue = getFieldsValue(); | ||
49 | + await updateEnterPriseDetail({ | ||
50 | + ...fieldsValue, | ||
51 | + codeProv: fieldsValue.nameProv, | ||
52 | + codeCity: fieldsValue.nameCity, | ||
53 | + codeCoun: fieldsValue.nameCoun, | ||
54 | + codeTown: fieldsValue.nameTown, | ||
55 | + }); | ||
56 | + compState.value.loading = false; | ||
57 | + createMessage.success('更新信息成功'); | ||
58 | + } catch (e) { | ||
59 | + createMessage.error('更新信息失败'); | ||
60 | + } | ||
61 | + }; | ||
62 | + onMounted(async () => { | ||
63 | + const res = await getEnterPriseDetail(); | ||
64 | + setFieldsValue(res); | ||
65 | + }); | ||
66 | + | ||
67 | + return { | ||
68 | + registerForm, | ||
69 | + compState, | ||
70 | + handleUpdateInfo, | ||
71 | + }; | ||
72 | + }, | ||
73 | + }); | ||
74 | +</script> | ||
75 | + | ||
76 | +<style lang="less" scoped></style> |
1 | +import type { FormSchema } from '/@/components/Form/index'; | ||
2 | +export const schemas: FormSchema[] = [ | ||
3 | + { | ||
4 | + field: 'name', | ||
5 | + component: 'Input', | ||
6 | + label: '平台名称', | ||
7 | + colProps: { | ||
8 | + span: 24, | ||
9 | + }, | ||
10 | + componentProps: { | ||
11 | + placeholder: '请输入平台名称', | ||
12 | + }, | ||
13 | + }, | ||
14 | + { | ||
15 | + field: 'logo', | ||
16 | + component: 'Upload', | ||
17 | + label: '平台Logo', | ||
18 | + colProps: { | ||
19 | + span: 24, | ||
20 | + }, | ||
21 | + slot: 'logoUpload', | ||
22 | + }, | ||
23 | + { | ||
24 | + field: 'background', | ||
25 | + component: 'Input', | ||
26 | + label: '登录页背景图片', | ||
27 | + colProps: { | ||
28 | + span: 24, | ||
29 | + }, | ||
30 | + slot: 'bgUpload', | ||
31 | + }, | ||
32 | + { | ||
33 | + field: 'backgroundColor', | ||
34 | + component: 'AutoComplete', | ||
35 | + label: '登录页背景颜色', | ||
36 | + colProps: { | ||
37 | + span: 24, | ||
38 | + }, | ||
39 | + slot: 'colorInput', | ||
40 | + }, | ||
41 | + { | ||
42 | + field: 'background', | ||
43 | + component: 'Input', | ||
44 | + label: '首页轮播图', | ||
45 | + colProps: { | ||
46 | + span: 24, | ||
47 | + }, | ||
48 | + slot: 'homeSwiper', | ||
49 | + }, | ||
50 | +]; |
1 | +import type { FormSchema } from '/@/components/Form/index'; | ||
2 | + | ||
3 | +export const schemas: FormSchema[] = [ | ||
4 | + { | ||
5 | + field: 'name', | ||
6 | + component: 'Input', | ||
7 | + label: '平台名称', | ||
8 | + colProps: { | ||
9 | + span: 24, | ||
10 | + }, | ||
11 | + componentProps: { | ||
12 | + placeholder: '请输入平台名称', | ||
13 | + }, | ||
14 | + }, | ||
15 | + { | ||
16 | + field: 'logo', | ||
17 | + component: 'Upload', | ||
18 | + label: '平台Logo', | ||
19 | + colProps: { | ||
20 | + span: 24, | ||
21 | + }, | ||
22 | + slot: 'logoUpload', | ||
23 | + }, | ||
24 | + { | ||
25 | + field: 'icon', | ||
26 | + component: 'Upload', | ||
27 | + label: 'Favicon浏览器Icon图标', | ||
28 | + colProps: { | ||
29 | + span: 24, | ||
30 | + }, | ||
31 | + slot: 'iconUpload', | ||
32 | + }, | ||
33 | + { | ||
34 | + field: 'background', | ||
35 | + component: 'Input', | ||
36 | + label: '登录页背景图片', | ||
37 | + colProps: { | ||
38 | + span: 24, | ||
39 | + }, | ||
40 | + slot: 'bgUpload', | ||
41 | + }, | ||
42 | + { | ||
43 | + field: 'backgroundColor', | ||
44 | + component: 'AutoComplete', | ||
45 | + label: '登录页背景颜色', | ||
46 | + colProps: { | ||
47 | + span: 24, | ||
48 | + }, | ||
49 | + slot: 'colorInput', | ||
50 | + }, | ||
51 | + { | ||
52 | + field: 'copyright', | ||
53 | + component: 'Input', | ||
54 | + label: '页面底部版权信息', | ||
55 | + colProps: { | ||
56 | + span: 24, | ||
57 | + }, | ||
58 | + }, | ||
59 | + { | ||
60 | + field: 'presentedOurselves', | ||
61 | + component: 'Input', | ||
62 | + label: '备案信息', | ||
63 | + colProps: { | ||
64 | + span: 24, | ||
65 | + }, | ||
66 | + }, | ||
67 | + { | ||
68 | + field: 'domain', | ||
69 | + component: 'Input', | ||
70 | + label: '绑定域名', | ||
71 | + colProps: { | ||
72 | + span: 24, | ||
73 | + }, | ||
74 | + }, | ||
75 | +]; |
1 | +import type { FormSchema } from '/@/components/Form/index'; | ||
2 | +import { getTownList, getTownChild } from '/@/api/oem/index'; | ||
3 | + | ||
4 | +export const schemas: FormSchema[] = [ | ||
5 | + { | ||
6 | + field: 'name', | ||
7 | + component: 'Input', | ||
8 | + label: '公司名称', | ||
9 | + colProps: { | ||
10 | + span: 24, | ||
11 | + }, | ||
12 | + componentProps: { | ||
13 | + placeholder: '请输入公司名称', | ||
14 | + }, | ||
15 | + }, | ||
16 | + { | ||
17 | + field: 'abbreviation', | ||
18 | + component: 'Input', | ||
19 | + label: '公司简称', | ||
20 | + colProps: { | ||
21 | + span: 24, | ||
22 | + }, | ||
23 | + componentProps: { | ||
24 | + placeholder: '请输入公司简称', | ||
25 | + }, | ||
26 | + }, | ||
27 | + { | ||
28 | + field: 'officialWebsite', | ||
29 | + component: 'Input', | ||
30 | + label: '公司官网', | ||
31 | + colProps: { | ||
32 | + span: 24, | ||
33 | + }, | ||
34 | + componentProps: { | ||
35 | + placeholder: '请输入公司官网', | ||
36 | + }, | ||
37 | + }, | ||
38 | + { | ||
39 | + field: 'email', | ||
40 | + component: 'Input', | ||
41 | + label: '公司邮箱', | ||
42 | + colProps: { | ||
43 | + span: 24, | ||
44 | + }, | ||
45 | + | ||
46 | + componentProps: { | ||
47 | + placeholder: '请输入公司邮箱', | ||
48 | + }, | ||
49 | + }, | ||
50 | + { | ||
51 | + field: 'synopsis', | ||
52 | + component: 'InputTextArea', | ||
53 | + label: '公司简介', | ||
54 | + colProps: { | ||
55 | + span: 24, | ||
56 | + }, | ||
57 | + componentProps: { | ||
58 | + placeholder: '请输入公司简介', | ||
59 | + autoSize: { minRows: 8, maxRows: 12 }, | ||
60 | + showCount: true, | ||
61 | + }, | ||
62 | + }, | ||
63 | + { | ||
64 | + field: 'country', | ||
65 | + component: 'Select', | ||
66 | + label: '国家/地区', | ||
67 | + colProps: { | ||
68 | + span: 24, | ||
69 | + }, | ||
70 | + defaultValue: '1', | ||
71 | + componentProps: { | ||
72 | + placeholder: '请选择国家/地区', | ||
73 | + options: [ | ||
74 | + { | ||
75 | + label: '中国', | ||
76 | + value: '1', | ||
77 | + }, | ||
78 | + ], | ||
79 | + }, | ||
80 | + }, | ||
81 | + { | ||
82 | + field: 'nameProv', | ||
83 | + component: 'ApiSelect', | ||
84 | + label: '所在城市', | ||
85 | + colProps: { | ||
86 | + span: 5, | ||
87 | + }, | ||
88 | + componentProps: ({ formModel, formActionType }) => { | ||
89 | + return { | ||
90 | + api: getTownList, | ||
91 | + labelField: 'nameProv', | ||
92 | + valueField: 'codeProv', | ||
93 | + placeholder: '请选择省份', | ||
94 | + async onChange(value) { | ||
95 | + let nameCity = await getTownChild('codeProv', value); | ||
96 | + nameCity.forEach((item) => { | ||
97 | + item.label = item.nameCity; | ||
98 | + item.value = item.codeCity; | ||
99 | + }); | ||
100 | + const { updateSchema } = formActionType; | ||
101 | + if (value === undefined) { | ||
102 | + formModel.nameCity = undefined; // reset city value | ||
103 | + formModel.nameCoun = undefined; | ||
104 | + formModel.nameTown = undefined; | ||
105 | + nameCity = []; | ||
106 | + updateSchema({ | ||
107 | + field: 'nameCoun', | ||
108 | + componentProps: { | ||
109 | + options: [], | ||
110 | + }, | ||
111 | + }); | ||
112 | + updateSchema({ | ||
113 | + field: 'nameTown', | ||
114 | + componentProps: { | ||
115 | + options: [], | ||
116 | + }, | ||
117 | + }); | ||
118 | + } | ||
119 | + updateSchema({ | ||
120 | + field: 'nameCity', | ||
121 | + componentProps: () => { | ||
122 | + return { | ||
123 | + options: nameCity, | ||
124 | + placeholder: '请选择城市', | ||
125 | + async onChange(value) { | ||
126 | + // 获取区数据 | ||
127 | + let nameCoun = await getTownChild('codeCity', value); | ||
128 | + nameCoun.forEach((item) => { | ||
129 | + item.label = item.nameCoun; | ||
130 | + item.value = item.codeCoun; | ||
131 | + }); | ||
132 | + if (value === undefined) { | ||
133 | + formModel.nameCoun = undefined; // reset city value | ||
134 | + formModel.nameTown = undefined; | ||
135 | + nameCoun = []; | ||
136 | + updateSchema({ | ||
137 | + field: 'nameTown', | ||
138 | + componentProps: { | ||
139 | + options: [], | ||
140 | + }, | ||
141 | + }); | ||
142 | + } | ||
143 | + updateSchema({ | ||
144 | + field: 'nameCoun', | ||
145 | + componentProps: { | ||
146 | + // 请选择区 | ||
147 | + options: nameCoun, | ||
148 | + async onChange(value) { | ||
149 | + let nameTown = await getTownChild('codeCoun', value); | ||
150 | + nameTown.forEach((item) => { | ||
151 | + item.label = item.nameTown; | ||
152 | + item.value = item.codeTown; | ||
153 | + }); | ||
154 | + if (value === undefined) { | ||
155 | + formModel.nameTown = undefined; | ||
156 | + nameTown = []; | ||
157 | + } | ||
158 | + updateSchema({ | ||
159 | + field: 'nameTown', | ||
160 | + componentProps: { | ||
161 | + placeholder: '请选择街道/城镇', | ||
162 | + options: nameTown, | ||
163 | + }, | ||
164 | + }); | ||
165 | + }, | ||
166 | + }, | ||
167 | + }); | ||
168 | + }, | ||
169 | + }; | ||
170 | + }, | ||
171 | + }); | ||
172 | + }, | ||
173 | + }; | ||
174 | + }, | ||
175 | + }, | ||
176 | + { | ||
177 | + field: 'nameCity', | ||
178 | + component: 'Select', | ||
179 | + label: '', | ||
180 | + | ||
181 | + colProps: { | ||
182 | + span: 5, | ||
183 | + style: { | ||
184 | + marginLeft: '-80px', | ||
185 | + }, | ||
186 | + }, | ||
187 | + }, | ||
188 | + { | ||
189 | + field: 'nameCoun', | ||
190 | + component: 'Select', | ||
191 | + label: '', | ||
192 | + colProps: { | ||
193 | + span: 5, | ||
194 | + style: { | ||
195 | + marginLeft: '-160px', | ||
196 | + }, | ||
197 | + }, | ||
198 | + componentProps: { | ||
199 | + placeholder: '请选择区/县', | ||
200 | + }, | ||
201 | + }, | ||
202 | + { | ||
203 | + field: 'nameTown', | ||
204 | + component: 'Select', | ||
205 | + label: '', | ||
206 | + colProps: { | ||
207 | + span: 6, | ||
208 | + style: { | ||
209 | + marginLeft: '-160px', | ||
210 | + }, | ||
211 | + }, | ||
212 | + componentProps: { | ||
213 | + placeholder: '请选择街道/城镇', | ||
214 | + }, | ||
215 | + }, | ||
216 | + | ||
217 | + // { | ||
218 | + // field: 'nameProv', | ||
219 | + // label: '所在城市', | ||
220 | + // component: 'Cascader', | ||
221 | + // }, | ||
222 | + | ||
223 | + { | ||
224 | + field: 'address', | ||
225 | + component: 'Input', | ||
226 | + label: '详细地址', | ||
227 | + colProps: { | ||
228 | + span: 24, | ||
229 | + }, | ||
230 | + componentProps: { | ||
231 | + placeholder: '请输入详细地址', | ||
232 | + }, | ||
233 | + }, | ||
234 | + | ||
235 | + { | ||
236 | + field: 'contacts', | ||
237 | + component: 'Input', | ||
238 | + label: '联系人', | ||
239 | + colProps: { | ||
240 | + span: 24, | ||
241 | + }, | ||
242 | + componentProps: { | ||
243 | + placeholder: '请输入联系人', | ||
244 | + }, | ||
245 | + }, | ||
246 | + { | ||
247 | + field: 'tel', | ||
248 | + component: 'Input', | ||
249 | + label: '联系电话', | ||
250 | + colProps: { | ||
251 | + span: 24, | ||
252 | + }, | ||
253 | + componentProps: { | ||
254 | + placeholder: '请输入联系电话', | ||
255 | + }, | ||
256 | + }, | ||
257 | +]; |
src/views/tenant/platform/index.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="platform flex"> | ||
3 | + <Card class="tab-card" :bordered="false"> | ||
4 | + <Tabs v-model:activeKey="activeKey" tab-position="left"> | ||
5 | + <TabPane key="企业信息" tab="企业信息" /> | ||
6 | + <TabPane key="平台定制" tab="平台定制" /> | ||
7 | + <TabPane key="APP定制" tab="APP定制" /> | ||
8 | + </Tabs> | ||
9 | + </Card> | ||
10 | + | ||
11 | + <div style="width: 100%"> | ||
12 | + <div class="title">{{ activeKey }}</div> | ||
13 | + <EnterpriseInfo v-if="activeKey === '企业信息'" /> | ||
14 | + <CVIDraw v-else-if="activeKey === '平台定制'" /> | ||
15 | + <AppDraw v-else /> | ||
16 | + </div> | ||
17 | + </div> | ||
18 | +</template> | ||
19 | + | ||
20 | +<script lang="ts" setup> | ||
21 | + import { Tabs, TabPane, Card } from 'ant-design-vue'; | ||
22 | + import { ref } from 'vue'; | ||
23 | + import EnterpriseInfo from './components/EnterpriseInfo.vue'; | ||
24 | + import CVIDraw from './components/CVIDraw.vue'; | ||
25 | + import AppDraw from './components/AppDraw.vue'; | ||
26 | + const activeKey = ref('APP定制'); | ||
27 | +</script> | ||
28 | + | ||
29 | +<style lang="less" scoped> | ||
30 | + .title { | ||
31 | + width: 97.4%; | ||
32 | + height: 50px; | ||
33 | + margin: 20px; | ||
34 | + line-height: 50px; | ||
35 | + font-size: 18px; | ||
36 | + border-radius: 8px; | ||
37 | + background-color: #fff; | ||
38 | + padding-left: 10px; | ||
39 | + } | ||
40 | + .tab-card { | ||
41 | + margin: 20px 0 20px 20px; | ||
42 | + border-radius: 5px; | ||
43 | + } | ||
44 | + .card { | ||
45 | + margin: 20px; | ||
46 | + border-radius: 8px; | ||
47 | + } | ||
48 | +</style> |
src/views/tenant/platform/types/index.ts
0 → 100644