Commit 70954e52d2930942a2c35817e53ee97638867e44

Authored by sqy
1 parent 1d9b7b74

'fix:首页开发,wip:OEM定制开发'

  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 +};
... ...
  1 +export interface FileUploadResponse {
  2 + fileName: string;
  3 + fileDownloadUri: string;
  4 + fileType: string;
  5 + size: number;
  6 + fileStaticUri: string;
  7 +}
... ...
... ... @@ -196,8 +196,8 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
196 196 export const defHttp = createAxios();
197 197
198 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 3 <template v-for="(item, index) in growCardList" :key="item.title">
4 4 <div
5 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 8 <div class="growCardItem-top">
9 9 <img :src="item.imgUrl" style="width: 90px; height: 90px" />
... ... @@ -13,23 +13,31 @@
13 13 <img src="../../../../assets/images/tip.png" style="width: 20px; height: 20px" />
14 14 </div>
15 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 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 22 在线 {{ item.onLine }}
20 23 </div>
21 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 29 离线 {{ item.offLine }}
24 30 </div>
25 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 36 未激活 {{ item.inactive }}
28 37 </div>
29 38 </div>
30 39 </div>
31 40 </div>
32   -
33 41 <div class="growCardItem-bottom"> 今日新增 {{ item.newDay }}</div>
34 42 </div>
35 43 </template>
... ... @@ -43,7 +51,7 @@
43 51 .growCardItem {
44 52 height: 179px;
45 53 background-color: #fff;
46   - color: 666;
  54 + color: #666;
47 55 .growCardItem-top {
48 56 display: flex;
49 57 margin: 20px;
... ...
... ... @@ -17,15 +17,15 @@
17 17 <List item-layout="horizontal" :data-source="data">
18 18 <template #renderItem="{ item }">
19 19 <ListItem>
20   - <ListItemMeta description="有新的告警数据需要处理,现在就去查看吧">
  20 + <ListItemMeta :description="item.description">
21 21 <template #title>
22 22 <a href="https://www.antdv.com/">{{ item.title }}</a>
23 23 </template>
24 24 <template #avatar>
25   - <Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
  25 + <Avatar :src="item.avatar" />
26 26 </template>
27 27 </ListItemMeta>
28   - <template #extra> 7小时前 </template>
  28 + <template #extra> {{ item.date }} </template>
29 29 </ListItem>
30 30 </template>
31 31 </List>
... ... @@ -34,7 +34,7 @@
34 34 </Card>
35 35 <Card hoverable title="联系我们" :bordered="false">
36 36 <template #cover>
37   - <QrCode :value="qrCodeUrl" />
  37 + <QrCode :value="qrCodeUrl" class="flex justify-center" />
38 38 </template>
39 39 <CardMeta>
40 40 <template #description>
... ... @@ -48,9 +48,9 @@
48 48 </template>
49 49
50 50 <script lang="ts">
51   - import { defineComponent, ref, unref } from 'vue';
  51 + import { defineComponent, ref } from 'vue';
52 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 54 export default defineComponent({
55 55 components: {
56 56 Card,
... ... @@ -100,32 +100,44 @@
100 100 // 列表
101 101 interface DataItem {
102 102 title: string;
  103 + description: string;
  104 + avatar: string;
  105 + date: string;
103 106 }
104 107 const data: DataItem[] = [
105 108 {
106 109 title: '企业管理员',
  110 + description: '现在就来开创新的记录吧!',
  111 + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
  112 + date: '5分钟前',
107 113 },
108 114 {
109 115 title: '企业管理员',
  116 + description: '有新的告警数据需要处理,现在去查看吧',
  117 + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
  118 + date: '7小时前',
110 119 },
111 120 {
112 121 title: '管理员',
  122 + description: '有新的告警数据需要处理,现在去查看吧',
  123 + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
  124 + date: '6小时前',
113 125 },
114 126 {
115 127 title: '管理员',
  128 + description: '现在就来开创新的记录吧!',
  129 + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
  130 + date: '1小时前',
116 131 },
117 132 {
118 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 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 142 return {
131 143 activeKey,
... ... @@ -134,7 +146,6 @@
134 146 data,
135 147 helpDoc,
136 148 qrCodeUrl,
137   - download,
138 149 };
139 150 },
140 151 });
... ...
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 5 :active-tab-key="activeKey"
6 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 26 </Card>
11 27 </template>
12 28 <script lang="ts" setup>
13 29 import { ref } from 'vue';
14   - import { Card } from 'ant-design-vue';
  30 + import { Card, DatePicker } from 'ant-design-vue';
15 31 import VisitAnalysis from './VisitAnalysis.vue';
16 32 import VisitAnalysisBar from './VisitAnalysisBar.vue';
17 33
... ... @@ -27,8 +43,36 @@
27 43 tab: '消息量统计',
28 44 },
29 45 ];
30   -
  46 + const dateList = ref(['1小时', '1天', '7天', '30天']);
  47 + const activeIndex = ref(0);
31 48 function onTabChange(key) {
32 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 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 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 });
... ...
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>
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 12 {
13 13 imgUrl: '/src/assets/images/device-count.png',
14 14 title: '设备数(个)',
15   - value: '10,0000',
  15 + value: '10,000',
16 16 onLine: 2000,
17 17 offLine: 3000,
18 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 +];
... ...
  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>
... ...
  1 +export interface FileItem {
  2 + uid: string;
  3 + name?: string;
  4 + status?: string;
  5 + response?: string;
  6 + percent?: number;
  7 + url?: string;
  8 + preview?: string;
  9 + originFileObj?: any;
  10 +}
  11 +
  12 +export interface FileInfo {
  13 + file: FileItem;
  14 + fileList: FileItem[];
  15 +}
... ...