Commit 76e5628f93e882e66f23e50ed00d057dd00a5587
Merge branch 'sqy_dev' into 'main'
fix:首页开发,OEM定制开发 See merge request huang/yun-teng-iot-front!13
Showing
34 changed files
with
2165 additions
and
534 deletions
| ... | ... | @@ -15,7 +15,7 @@ enum API { |
| 15 | 15 | |
| 16 | 16 | // 获取 |
| 17 | 17 | export const getAlarmContact = (params: ContactPageParams) => { |
| 18 | - return getPageData<ContactModal>(params, Api.alarmContact); | |
| 18 | + return getPageData<ContactModal>(params, API.alarmContact); | |
| 19 | 19 | }; |
| 20 | 20 | |
| 21 | 21 | // 新增 |
| ... | ... | @@ -48,6 +48,7 @@ export const saveOrEditAlarmContact = (params: ContactInfo, isUpdate: boolean) = |
| 48 | 48 | addAlarmContact(params); |
| 49 | 49 | }; |
| 50 | 50 | |
| 51 | +// 查询设备分页数据 | |
| 51 | 52 | export const devicePage = (params: DeviceQueryParam) => { |
| 52 | 53 | return defHttp.get<DeviceModel>({ |
| 53 | 54 | url: API.devicePage, | ... | ... |
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
src/assets/images/alarm-count.png
0 → 100644
1.1 KB
src/assets/images/device-count.png
0 → 100644
1.15 KB
src/assets/images/flow.png
0 → 100644
417 KB
src/assets/images/inactive.png
0 → 100644
205 Bytes
src/assets/images/msg-count.png
0 → 100644
625 Bytes
src/assets/images/offline.png
0 → 100644
269 Bytes
src/assets/images/online.png
0 → 100644
232 Bytes
src/assets/images/tip.png
0 → 100644
589 Bytes
| ... | ... | @@ -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 | +}); | ... | ... |
| ... | ... | @@ -33,6 +33,7 @@ |
| 33 | 33 | 'https://api.map.baidu.com/getscript?v=3.0&ak=7uOPPyAHn2Y2ZryeQqHtcRqtIY374vKa'; |
| 34 | 34 | const wrapRef = ref<HTMLDivElement | null>(null); |
| 35 | 35 | const { toPromise } = useScript({ src: BAI_DU_MAP_URL }); |
| 36 | + | |
| 36 | 37 | async function initMap() { |
| 37 | 38 | await toPromise(); |
| 38 | 39 | await nextTick(); | ... | ... |
| 1 | 1 | <template> |
| 2 | 2 | <div class="md:flex"> |
| 3 | 3 | <template v-for="(item, index) in growCardList" :key="item.title"> |
| 4 | - <Card | |
| 5 | - size="small" | |
| 6 | - :loading="$attrs.loading" | |
| 7 | - :title="item.title" | |
| 8 | - class="md:w-1/4 w-full !md:mt-0 !mt-4" | |
| 9 | - :class="[index + 1 < 4 && '!md:mr-4']" | |
| 10 | - :canExpan="false" | |
| 4 | + <div | |
| 5 | + class="growCardItem md:w-1/3 w-full !md:mt-0 !mt-4 !md:mr-4" | |
| 6 | + :class="[index + 1 < 3 && '!md:mr-4']" | |
| 11 | 7 | > |
| 12 | - <template #extra> | |
| 13 | - <Tag :color="item.color">{{ item.action }}</Tag> | |
| 14 | - </template> | |
| 15 | - | |
| 16 | - <div class="py-4 px-4 flex justify-between"> | |
| 17 | - <CountTo prefix="$" :startVal="1" :endVal="item.value" class="text-2xl" /> | |
| 18 | - <Icon :icon="item.icon" :size="40" /> | |
| 19 | - </div> | |
| 20 | - | |
| 21 | - <div class="p-2 px-4 flex justify-between"> | |
| 22 | - <span>总{{ item.title }}</span> | |
| 23 | - <CountTo prefix="$" :startVal="1" :endVal="item.total" /> | |
| 8 | + <div class="growCardItem-top"> | |
| 9 | + <img :src="item.imgUrl" style="width: 90px; height: 90px" /> | |
| 10 | + <div class="growCardItem-right"> | |
| 11 | + <div class="flex justify-between ml-3"> | |
| 12 | + <div style="font-size: 26px; color: #333">{{ item.value }}</div> | |
| 13 | + <img src="../../../../assets/images/tip.png" style="width: 20px; height: 20px" /> | |
| 14 | + </div> | |
| 15 | + <div class="ml-3">{{ item.title }}</div> | |
| 16 | + <div class="ml-1.5 mt-3 flex flex-nowrap" style="width: 240px" v-if="item.offLine"> | |
| 17 | + <div class="count"> | |
| 18 | + <img | |
| 19 | + src="../../../../assets/images/online.png" | |
| 20 | + style="width: 10px; height: 10px; margin-right: 4px" | |
| 21 | + /> | |
| 22 | + 在线 {{ item.onLine }} | |
| 23 | + </div> | |
| 24 | + <div class="count"> | |
| 25 | + <img | |
| 26 | + src="../../../../assets/images/offline.png" | |
| 27 | + style="width: 10px; height: 10px; margin-right: 4px" | |
| 28 | + /> | |
| 29 | + 离线 {{ item.offLine }} | |
| 30 | + </div> | |
| 31 | + <div class="count"> | |
| 32 | + <img | |
| 33 | + src="../../../../assets/images/inactive.png" | |
| 34 | + style="width: 10px; height: 10px; margin-right: 4px" | |
| 35 | + /> | |
| 36 | + 未激活 {{ item.inactive }} | |
| 37 | + </div> | |
| 38 | + </div> | |
| 39 | + </div> | |
| 24 | 40 | </div> |
| 25 | - </Card> | |
| 41 | + <div class="growCardItem-bottom"> 今日新增 {{ item.newDay }}</div> | |
| 42 | + </div> | |
| 26 | 43 | </template> |
| 27 | 44 | </div> |
| 28 | 45 | </template> |
| 29 | 46 | <script lang="ts" setup> |
| 30 | - import { CountTo } from '/@/components/CountTo/index'; | |
| 31 | - import { Icon } from '/@/components/Icon'; | |
| 32 | - import { Tag, Card } from 'ant-design-vue'; | |
| 33 | 47 | import { growCardList } from '../data'; |
| 34 | 48 | </script> |
| 49 | + | |
| 50 | +<style scoped lang="less"> | |
| 51 | + .growCardItem { | |
| 52 | + height: 179px; | |
| 53 | + background-color: #fff; | |
| 54 | + color: #666; | |
| 55 | + .growCardItem-top { | |
| 56 | + display: flex; | |
| 57 | + margin: 20px; | |
| 58 | + border-bottom: 1px solid #f2f2f5; | |
| 59 | + padding-bottom: 10px; | |
| 60 | + .growCardItem-right { | |
| 61 | + width: 300px; | |
| 62 | + .count { | |
| 63 | + display: flex; | |
| 64 | + font-size: 12px; | |
| 65 | + align-items: center; | |
| 66 | + margin-left: 8px; | |
| 67 | + } | |
| 68 | + } | |
| 69 | + } | |
| 70 | + .growCardItem-bottom { | |
| 71 | + margin-left: 20px; | |
| 72 | + } | |
| 73 | + } | |
| 74 | +</style> | ... | ... |
| 1 | +<template> | |
| 2 | + <Card title="帮助文档"> | |
| 3 | + <div> | |
| 4 | + <template v-for="item in helpDoc" :key="item.title"> | |
| 5 | + <AnchorLink v-bind="item" /> | |
| 6 | + </template> | |
| 7 | + </div> | |
| 8 | + <Card | |
| 9 | + :tab-list="tabListTitle" | |
| 10 | + v-bind="$attrs" | |
| 11 | + :active-tab-key="activeKey" | |
| 12 | + :bordered="false" | |
| 13 | + @tabChange="onTabChange" | |
| 14 | + :bodyStyle="{ padding: 0 }" | |
| 15 | + > | |
| 16 | + <div v-if="activeKey === 'tab1'"> | |
| 17 | + <List item-layout="horizontal" :data-source="data"> | |
| 18 | + <template #renderItem="{ item }"> | |
| 19 | + <ListItem> | |
| 20 | + <ListItemMeta :description="item.description"> | |
| 21 | + <template #title> | |
| 22 | + <a href="https://www.antdv.com/">{{ item.title }}</a> | |
| 23 | + </template> | |
| 24 | + <template #avatar> | |
| 25 | + <Avatar :src="item.avatar" /> | |
| 26 | + </template> | |
| 27 | + </ListItemMeta> | |
| 28 | + <template #extra> {{ item.date }} </template> | |
| 29 | + </ListItem> | |
| 30 | + </template> | |
| 31 | + </List> | |
| 32 | + </div> | |
| 33 | + <div v-else>222</div> | |
| 34 | + </Card> | |
| 35 | + <Card hoverable title="联系我们" :bordered="false"> | |
| 36 | + <template #cover> | |
| 37 | + <QrCode :value="qrCodeUrl" class="flex justify-center" /> | |
| 38 | + </template> | |
| 39 | + <CardMeta> | |
| 40 | + <template #description> | |
| 41 | + <p>联系人: 张三</p> | |
| 42 | + <p>联系电话: 15912341234</p> | |
| 43 | + <p>联系地址: 四川省成都市剑南大道北段中1533号 </p> | |
| 44 | + </template> | |
| 45 | + </CardMeta> | |
| 46 | + </Card> | |
| 47 | + </Card> | |
| 48 | +</template> | |
| 49 | + | |
| 50 | +<script lang="ts"> | |
| 51 | + import { defineComponent, ref } from 'vue'; | |
| 52 | + import { Card, AnchorLink, List, ListItem, ListItemMeta, Avatar, CardMeta } from 'ant-design-vue'; | |
| 53 | + import { QrCode } from '/@/components/Qrcode/index'; | |
| 54 | + export default defineComponent({ | |
| 55 | + components: { | |
| 56 | + Card, | |
| 57 | + AnchorLink, | |
| 58 | + List, | |
| 59 | + ListItem, | |
| 60 | + ListItemMeta, | |
| 61 | + Avatar, | |
| 62 | + CardMeta, | |
| 63 | + QrCode, | |
| 64 | + }, | |
| 65 | + setup() { | |
| 66 | + const helpDoc = ref([ | |
| 67 | + { | |
| 68 | + title: '如何接入设备?', | |
| 69 | + href: '', | |
| 70 | + }, | |
| 71 | + { | |
| 72 | + title: '什么是设备配置?', | |
| 73 | + href: '', | |
| 74 | + }, | |
| 75 | + { | |
| 76 | + title: '云组态模板如何使用?', | |
| 77 | + href: '', | |
| 78 | + }, | |
| 79 | + { | |
| 80 | + title: '查看全部>>', | |
| 81 | + href: '', | |
| 82 | + }, | |
| 83 | + ]); | |
| 84 | + | |
| 85 | + const activeKey = ref('tab1'); | |
| 86 | + const tabListTitle = [ | |
| 87 | + { | |
| 88 | + key: 'tab1', | |
| 89 | + tab: '通知公告', | |
| 90 | + }, | |
| 91 | + { | |
| 92 | + key: 'tab2', | |
| 93 | + tab: '系统公告', | |
| 94 | + }, | |
| 95 | + ]; | |
| 96 | + const onTabChange = (key) => { | |
| 97 | + activeKey.value = key; | |
| 98 | + }; | |
| 99 | + | |
| 100 | + // 列表 | |
| 101 | + interface DataItem { | |
| 102 | + title: string; | |
| 103 | + description: string; | |
| 104 | + avatar: string; | |
| 105 | + date: string; | |
| 106 | + } | |
| 107 | + const data: DataItem[] = [ | |
| 108 | + { | |
| 109 | + title: '企业管理员', | |
| 110 | + description: '现在就来开创新的记录吧!', | |
| 111 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | |
| 112 | + date: '5分钟前', | |
| 113 | + }, | |
| 114 | + { | |
| 115 | + title: '企业管理员', | |
| 116 | + description: '有新的告警数据需要处理,现在去查看吧', | |
| 117 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | |
| 118 | + date: '7小时前', | |
| 119 | + }, | |
| 120 | + { | |
| 121 | + title: '管理员', | |
| 122 | + description: '有新的告警数据需要处理,现在去查看吧', | |
| 123 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | |
| 124 | + date: '6小时前', | |
| 125 | + }, | |
| 126 | + { | |
| 127 | + title: '管理员', | |
| 128 | + description: '现在就来开创新的记录吧!', | |
| 129 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | |
| 130 | + date: '1小时前', | |
| 131 | + }, | |
| 132 | + { | |
| 133 | + title: '管理员', | |
| 134 | + description: '现在就来开创新的记录吧!', | |
| 135 | + avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png', | |
| 136 | + date: '7小时前', | |
| 137 | + }, | |
| 138 | + ]; | |
| 139 | + | |
| 140 | + const qrCodeUrl = 'https://www.vvbin.cn'; | |
| 141 | + | |
| 142 | + return { | |
| 143 | + activeKey, | |
| 144 | + tabListTitle, | |
| 145 | + onTabChange, | |
| 146 | + data, | |
| 147 | + helpDoc, | |
| 148 | + qrCodeUrl, | |
| 149 | + }; | |
| 150 | + }, | |
| 151 | + }); | |
| 152 | +</script> | |
| 153 | + | |
| 154 | +<style lang="less" scoped></style> | ... | ... |
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,17 +5,29 @@ |
| 5 | 5 | :active-tab-key="activeKey" |
| 6 | 6 | @tabChange="onTabChange" |
| 7 | 7 | > |
| 8 | - <p v-if="activeKey === 'tab1'"> | |
| 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> | |
| 9 | 20 | <VisitAnalysis /> |
| 10 | - </p> | |
| 11 | - <p v-if="activeKey === 'tab2'"> | |
| 21 | + </div> | |
| 22 | + <div v-else> | |
| 23 | + <p class="center">消息数</p> | |
| 12 | 24 | <VisitAnalysisBar /> |
| 13 | - </p> | |
| 25 | + </div> | |
| 14 | 26 | </Card> |
| 15 | 27 | </template> |
| 16 | 28 | <script lang="ts" setup> |
| 17 | 29 | import { ref } from 'vue'; |
| 18 | - import { Card } from 'ant-design-vue'; | |
| 30 | + import { Card, DatePicker } from 'ant-design-vue'; | |
| 19 | 31 | import VisitAnalysis from './VisitAnalysis.vue'; |
| 20 | 32 | import VisitAnalysisBar from './VisitAnalysisBar.vue'; |
| 21 | 33 | |
| ... | ... | @@ -24,15 +36,43 @@ |
| 24 | 36 | const tabListTitle = [ |
| 25 | 37 | { |
| 26 | 38 | key: 'tab1', |
| 27 | - tab: '流量趋势', | |
| 39 | + tab: '告警数统计', | |
| 28 | 40 | }, |
| 29 | 41 | { |
| 30 | 42 | key: 'tab2', |
| 31 | - tab: '访问量', | |
| 43 | + tab: '消息量统计', | |
| 32 | 44 | }, |
| 33 | 45 | ]; |
| 34 | - | |
| 46 | + const dateList = ref(['1小时', '1天', '7天', '30天']); | |
| 47 | + const activeIndex = ref(0); | |
| 35 | 48 | function onTabChange(key) { |
| 36 | 49 | activeKey.value = key; |
| 37 | 50 | } |
| 51 | + function onDateChange(date, dateString) { | |
| 52 | + console.log(date, dateString); | |
| 53 | + } | |
| 54 | + function changeDate(index: number) { | |
| 55 | + activeIndex.value = index; | |
| 56 | + } | |
| 38 | 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 | }); | ... | ... |
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> |
| 1 | 1 | export interface GrowCardItem { |
| 2 | - icon: string; | |
| 2 | + imgUrl: string; | |
| 3 | 3 | title: string; |
| 4 | - value: number; | |
| 5 | - total: number; | |
| 6 | - color: string; | |
| 7 | - action: string; | |
| 4 | + value: string; | |
| 5 | + onLine?: number; | |
| 6 | + offLine?: number; | |
| 7 | + inactive?: number; | |
| 8 | + newDay: string; | |
| 8 | 9 | } |
| 9 | 10 | |
| 10 | 11 | export const growCardList: GrowCardItem[] = [ |
| 11 | 12 | { |
| 12 | - title: '访问数', | |
| 13 | - icon: 'visit-count|svg', | |
| 14 | - value: 2000, | |
| 15 | - total: 120000, | |
| 16 | - color: 'green', | |
| 17 | - action: '月', | |
| 13 | + imgUrl: '/src/assets/images/device-count.png', | |
| 14 | + title: '设备数(个)', | |
| 15 | + value: '10,000', | |
| 16 | + onLine: 2000, | |
| 17 | + offLine: 3000, | |
| 18 | + inactive: 4000, | |
| 19 | + newDay: '123,45', | |
| 18 | 20 | }, |
| 19 | 21 | { |
| 20 | - title: '成交额', | |
| 21 | - icon: 'total-sales|svg', | |
| 22 | - value: 20000, | |
| 23 | - total: 500000, | |
| 24 | - color: 'blue', | |
| 25 | - action: '月', | |
| 22 | + imgUrl: '/src/assets/images/alarm-count.png', | |
| 23 | + title: '11月告警数(条)', | |
| 24 | + value: '11,000', | |
| 25 | + newDay: '167,45', | |
| 26 | 26 | }, |
| 27 | 27 | { |
| 28 | - title: '下载数', | |
| 29 | - icon: 'download-count|svg', | |
| 30 | - value: 8000, | |
| 31 | - total: 120000, | |
| 32 | - color: 'orange', | |
| 33 | - action: '周', | |
| 34 | - }, | |
| 35 | - { | |
| 36 | - title: '成交数', | |
| 37 | - icon: 'transaction|svg', | |
| 38 | - value: 5000, | |
| 39 | - total: 50000, | |
| 40 | - color: 'purple', | |
| 41 | - action: '年', | |
| 28 | + imgUrl: '/src/assets/images/msg-count.png', | |
| 29 | + title: '11月消息量(条)', | |
| 30 | + value: '12,000', | |
| 31 | + newDay: '198,45', | |
| 42 | 32 | }, |
| 43 | 33 | ]; | ... | ... |
| 1 | 1 | <template> |
| 2 | - <div class="p-4"> | |
| 3 | - <GrowCard :loading="loading" class="enter-y" /> | |
| 4 | - <SiteAnalysis class="!my-4 enter-y" :loading="loading" /> | |
| 5 | - <div class="md:flex enter-y"> | |
| 6 | - <VisitRadar class="md:w-1/3 w-full" :loading="loading" /> | |
| 7 | - <VisitSource class="md:w-1/3 !md:mx-4 !md:my-0 !my-4 w-full" :loading="loading" /> | |
| 8 | - <SalesProductPie class="md:w-1/3 w-full" :loading="loading" /> | |
| 2 | + <div class="p-4 md:flex"> | |
| 3 | + <div class="md:w-7/10 w-full !mr-4 enter-y"> | |
| 4 | + <GrowCard :loading="loading" class="enter-y" /> | |
| 5 | + <SiteAnalysis class="!my-4 enter-y" :loading="loading" /> | |
| 6 | + <div class="md:flex enter-y"> | |
| 7 | + <Card title="核心流程指南" style="width: 100%"> | |
| 8 | + <img alt="核心流程指南" src="../../../assets/images/flow.png" /> | |
| 9 | + </Card> | |
| 10 | + </div> | |
| 11 | + </div> | |
| 12 | + <div class="md:w-3/10 w-full enter-y"> | |
| 13 | + <HelpDoc /> | |
| 9 | 14 | </div> |
| 10 | 15 | </div> |
| 11 | 16 | </template> |
| ... | ... | @@ -13,12 +18,9 @@ |
| 13 | 18 | import { ref } from 'vue'; |
| 14 | 19 | import GrowCard from './components/GrowCard.vue'; |
| 15 | 20 | import SiteAnalysis from './components/SiteAnalysis.vue'; |
| 16 | - import VisitSource from './components/VisitSource.vue'; | |
| 17 | - import VisitRadar from './components/VisitRadar.vue'; | |
| 18 | - import SalesProductPie from './components/SalesProductPie.vue'; | |
| 19 | - | |
| 21 | + import { Card } from 'ant-design-vue'; | |
| 22 | + import HelpDoc from './components/HelpDoc.vue'; | |
| 20 | 23 | const loading = ref(true); |
| 21 | - | |
| 22 | 24 | setTimeout(() => { |
| 23 | 25 | loading.value = false; |
| 24 | 26 | }, 1500); | ... | ... |
| 1 | 1 | <template> |
| 2 | 2 | <div class="step3"> |
| 3 | - <h1 v-if="alarmList.length === 0" style="font-size: 24px" class="text-center" | |
| 4 | - >未配置报警规则</h1 | |
| 5 | - > | |
| 6 | - | |
| 7 | - <template v-else v-for="(item, index) in alarmList" :key="item"> | |
| 8 | - <CollapseContainer :title="item.alarmType" style="border: 1px solid #bfbfbf" class="mb-6"> | |
| 3 | + <template v-for="(item, index) in alarmList" :key="item.id"> | |
| 4 | + <CollapseContainer class="border mb-8"> | |
| 9 | 5 | <template #action> |
| 10 | - <div @click="handleDeleteAlarm(index)" class="cursor-pointer"> | |
| 6 | + <div @click="deleteAlarmRule(index)" class="cursor-pointer"> | |
| 11 | 7 | <DeleteOutlined style="font-size: 20px" class="mr-2" /> |
| 12 | 8 | </div> |
| 13 | 9 | </template> |
| 14 | - <a-form :wrapper-col="wrapperCol" labelAlign="left" :model="item" :rules="rules"> | |
| 15 | - <a-form-item label="报警类型" :labelCol="{ style: { width: '80px' } }" name="alarmType"> | |
| 16 | - <a-input v-model:value="item.alarmType" /> | |
| 17 | - </a-form-item> | |
| 18 | - </a-form> | |
| 19 | - | |
| 10 | + <BasicForm @register="registerForm" /> | |
| 20 | 11 | <CollapseContainer> |
| 21 | 12 | <template #action> 高级设置 </template> |
| 22 | - <div class="flex" style="align-items: center"> | |
| 23 | - <input type="checkbox" v-model="item.isPass" /> <div class="ml-2">传递警报</div> | |
| 24 | - </div> | |
| 25 | - | |
| 26 | - <a-form :wrapper-col="wrapperCol" labelAlign="left" v-if="item.isPass"> | |
| 27 | - <a-form-item label="传递的关联类型" :labelCol="{ style: { width: '120px' } }"> | |
| 28 | - <a-input /> | |
| 29 | - </a-form-item> | |
| 30 | - </a-form> | |
| 13 | + <BasicForm @register="registerFormHighSetting"> | |
| 14 | + <template #checkBox="{ model, field }"> | |
| 15 | + <Checkbox v-model:checked="model[field]">传递报警</Checkbox> | |
| 16 | + </template> | |
| 17 | + </BasicForm> | |
| 31 | 18 | </CollapseContainer> |
| 32 | - <p style="color: #3c3c3c">创建报警规则</p> | |
| 33 | - <template v-for="(item1, index1) in item.alarmRule" :key="item1"> | |
| 34 | - <div class="alarm-rule mb-4"> | |
| 35 | - <div style="width: 90%; border: 2px solid #8c8c8c; border-radius: 5px" class="flex"> | |
| 36 | - <div style="width: 30%; height: 100%; border-right: 1px solid #e0e0e0"> | |
| 37 | - <span style="color: #305680; margin-left: 10px">严重程度</span> | |
| 38 | - <a-select :options="options" style="width: 100px; margin-left: 10px" /> | |
| 39 | - </div> | |
| 40 | - <div style="width: 70%; height: 100%"> | |
| 19 | + <p>创建报警规则</p> | |
| 20 | + <template v-for="(createItem, createIndex) in item.createRule" :key="createItem.id"> | |
| 21 | + <div class="aic mb-4" style="border: 1px solid #bfbfbf"> | |
| 22 | + <div class="w-3/4"> | |
| 23 | + <BasicForm @register="registerFormCreateAlarm" /> | |
| 24 | + <div> | |
| 41 | 25 | <p style="color: #f5594e" class="mt-4 ml-4" |
| 42 | 26 | >请添加报警规则条件 |
| 43 | 27 | <PlusOutlined class="cursor-pointer ml-4" style="font-size: 20px" |
| ... | ... | @@ -47,68 +31,29 @@ |
| 47 | 31 | <EditOutlined class="cursor-pointer ml-4" style="font-size: 20px" |
| 48 | 32 | /></p> |
| 49 | 33 | <p class="mt-4 ml-4" |
| 50 | - >详情:1 | |
| 51 | - <EditOutlined | |
| 52 | - @click="editCreateDetail(index, index1)" | |
| 53 | - class="cursor-pointer ml-4" | |
| 54 | - style="font-size: 20px" | |
| 34 | + >详情:<EditOutlined class="cursor-pointer ml-4" style="font-size: 20px" | |
| 55 | 35 | /></p> |
| 56 | - <p class="mt-4 ml-4">dashboard: <a-select style="width: 180px" /></p> | |
| 36 | + <p class="mt-4 ml-4">dashboard:</p> | |
| 57 | 37 | </div> |
| 58 | 38 | </div> |
| 59 | - <div style="width: 10%" class="alarm-remove"> | |
| 60 | - <a-tooltip title="移除"> | |
| 39 | + <div class="w-1/4 flex justify-center"> | |
| 40 | + <Tooltip title="移除"> | |
| 61 | 41 | <MinusCircleOutlined |
| 62 | - style="font-size: 25px color:#305680" | |
| 42 | + style="font-size: 25px; color: #305680" | |
| 63 | 43 | class="cursor-pointer" |
| 64 | - @click="handleDeleteCondition(index, index1)" | |
| 44 | + @click="deleteCondition(index, createIndex)" | |
| 65 | 45 | /> |
| 66 | - </a-tooltip> | |
| 46 | + </Tooltip> | |
| 67 | 47 | </div> |
| 68 | 48 | </div> |
| 69 | 49 | </template> |
| 70 | 50 | <a-button class="mt-5" @click="addCreateRole(index)" |
| 71 | 51 | ><PlusCircleOutlined />添加创建条件</a-button |
| 72 | 52 | > |
| 73 | - <!-- 创建报警规则的弹框 --> | |
| 74 | - <a-modal v-model:visible="visible" title="详情" centered> | |
| 75 | - <a-textarea placeholder="报警详细信息" :rows="4" /> | |
| 76 | - </a-modal> | |
| 77 | - | |
| 78 | - <p style="color: #3c3c3c">清除报警规则</p> | |
| 79 | - <template v-for="(item2, index2) in item.removeRule" :key="item2"> | |
| 80 | - <div class="alarm-rule mb-4"> | |
| 81 | - <div style="width: 90%; border: 2px solid #8c8c8c; border-radius: 5px" class="flex"> | |
| 82 | - <div style="width: 70%; height: 100%"> | |
| 83 | - <p style="color: #f5594e" class="mt-4 ml-4" | |
| 84 | - >请添加报警规则条件 | |
| 85 | - <PlusOutlined class="cursor-pointer ml-4" style="font-size: 20px" | |
| 86 | - /></p> | |
| 87 | - <p class="mt-4 ml-4" | |
| 88 | - >启用规则:始终启用 | |
| 89 | - <EditOutlined class="cursor-pointer ml-4" style="font-size: 20px" | |
| 90 | - /></p> | |
| 91 | - <p class="mt-4 ml-4" | |
| 92 | - >详情:1 <EditOutlined class="cursor-pointer ml-4" style="font-size: 20px" /> | |
| 93 | - </p> | |
| 94 | - | |
| 95 | - <p class="mt-4 ml-4">Mobile dashboard: <a-select style="width: 150px" /></p> | |
| 96 | - </div> | |
| 97 | - </div> | |
| 98 | - <div style="width: 10%" class="alarm-remove"> | |
| 99 | - <a-tooltip title="移除"> | |
| 100 | - <MinusCircleOutlined | |
| 101 | - style="font-size: 25px color:#305680" | |
| 102 | - class="cursor-pointer" | |
| 103 | - @click="handleDeleteRemoveCondition(index, index2)" | |
| 104 | - /> | |
| 105 | - </a-tooltip> | |
| 106 | - </div> | |
| 107 | - </div> | |
| 108 | - </template> | |
| 109 | - <a-button class="mt-5" @click="addRemoveRule(index)" | |
| 110 | - ><PlusCircleOutlined />添加清除条件</a-button | |
| 111 | - > | |
| 53 | + <p>清除报警规则</p> | |
| 54 | + <BasicForm @register="registerFormClearAlarm"> | |
| 55 | + <template #formHeader> </template> | |
| 56 | + </BasicForm> | |
| 112 | 57 | </CollapseContainer> |
| 113 | 58 | </template> |
| 114 | 59 | <div class="flex justify-start"> |
| ... | ... | @@ -117,163 +62,156 @@ |
| 117 | 62 | </div> |
| 118 | 63 | </div> |
| 119 | 64 | </template> |
| 65 | + | |
| 120 | 66 | <script lang="ts"> |
| 121 | - import { defineComponent, ref } from 'vue'; | |
| 122 | - import { | |
| 123 | - Alert, | |
| 124 | - Divider, | |
| 125 | - Descriptions, | |
| 126 | - Input, | |
| 127 | - Form, | |
| 128 | - Button, | |
| 129 | - Select, | |
| 130 | - Tooltip, | |
| 131 | - Modal, | |
| 132 | - Textarea, | |
| 133 | - } from 'ant-design-vue'; | |
| 67 | + import { defineComponent, ref, unref } from 'vue'; | |
| 68 | + import type { alarmListItem } from '../types/index'; | |
| 69 | + import { CollapseContainer } from '/@/components/Container/index'; | |
| 70 | + import { BasicForm, useForm } from '/@/components/Form'; | |
| 71 | + import { step3Schemas, step3HighSetting, step3CreateAlarm, step3ClearAlarm } from './data'; | |
| 134 | 72 | import { |
| 135 | 73 | DeleteOutlined, |
| 136 | 74 | MinusCircleOutlined, |
| 137 | 75 | PlusCircleOutlined, |
| 138 | 76 | PlusOutlined, |
| 139 | 77 | EditOutlined, |
| 78 | + CloseOutlined, | |
| 140 | 79 | } from '@ant-design/icons-vue'; |
| 141 | - | |
| 142 | - import { CollapseContainer } from '/@/components/Container/index'; | |
| 143 | - interface alarmListItem { | |
| 144 | - alarmType: string; | |
| 145 | - isPass: boolean; | |
| 146 | - alarmRule: []; | |
| 147 | - removeRule: []; | |
| 148 | - } | |
| 80 | + import { Tooltip, Checkbox } from 'ant-design-vue'; | |
| 149 | 81 | export default defineComponent({ |
| 150 | 82 | components: { |
| 83 | + BasicForm, | |
| 84 | + CollapseContainer, | |
| 151 | 85 | DeleteOutlined, |
| 152 | 86 | MinusCircleOutlined, |
| 153 | 87 | PlusCircleOutlined, |
| 154 | - CollapseContainer, | |
| 155 | - EditOutlined, | |
| 156 | 88 | PlusOutlined, |
| 157 | - [Modal.name]: Modal, | |
| 158 | - [Textarea.name]: Textarea, | |
| 159 | - [Tooltip.name]: Tooltip, | |
| 160 | - [Button.name]: Button, | |
| 161 | - [Input.name]: Input, | |
| 162 | - [Select.name]: Select, | |
| 163 | - [Form.name]: Form, | |
| 164 | - [Form.Item.name]: Form.Item, | |
| 165 | - [Alert.name]: Alert, | |
| 166 | - [Divider.name]: Divider, | |
| 167 | - [Descriptions.name]: Descriptions, | |
| 168 | - [Descriptions.Item.name]: Descriptions.Item, | |
| 89 | + EditOutlined, | |
| 90 | + CloseOutlined, | |
| 91 | + Checkbox, | |
| 92 | + Tooltip, | |
| 169 | 93 | }, |
| 170 | 94 | emits: ['prev'], |
| 171 | 95 | setup(_, { emit }) { |
| 172 | - const alarmList = ref<alarmListItem[]>([]); | |
| 173 | - const visible = ref(false); | |
| 174 | - const options = ref([ | |
| 175 | - { | |
| 176 | - value: '1', | |
| 177 | - label: '危险', | |
| 178 | - }, | |
| 179 | - | |
| 180 | - { | |
| 181 | - value: '2', | |
| 182 | - label: '重要', | |
| 183 | - }, | |
| 184 | - { | |
| 185 | - value: '3', | |
| 186 | - label: '次要', | |
| 187 | - }, | |
| 188 | - { | |
| 189 | - value: '4', | |
| 190 | - label: '警告', | |
| 191 | - }, | |
| 192 | - { | |
| 193 | - value: '5', | |
| 194 | - label: '不确定', | |
| 195 | - }, | |
| 196 | - ]); | |
| 197 | - const rules = { | |
| 198 | - alarmType: [ | |
| 199 | - { | |
| 200 | - required: true, | |
| 201 | - message: '报警类型必填', | |
| 202 | - trigger: 'blur', | |
| 203 | - }, | |
| 204 | - ], | |
| 96 | + //告警列表 | |
| 97 | + let alarmList = ref<alarmListItem[]>([]); | |
| 98 | + // 添加和删除告警配置 | |
| 99 | + const deleteAlarmRule = (index: number) => { | |
| 100 | + unref(alarmList).splice(index, 1); | |
| 205 | 101 | }; |
| 206 | - | |
| 102 | + // 上一步 | |
| 207 | 103 | const prevStep = () => { |
| 208 | 104 | emit('prev'); |
| 209 | 105 | }; |
| 210 | - // 添加报警规则 | |
| 211 | 106 | const addAlarmRule = () => { |
| 212 | - alarmList.value.push({ | |
| 107 | + unref(alarmList).push({ | |
| 108 | + id: Date.now(), | |
| 213 | 109 | alarmType: '', |
| 214 | 110 | isPass: false, |
| 215 | - alarmRule: [], | |
| 216 | - removeRule: [], | |
| 111 | + createRule: [ | |
| 112 | + { | |
| 113 | + id: Date.now() + Math.random(), | |
| 114 | + alarmVisible: false, | |
| 115 | + addKeyFilterVisible: false, | |
| 116 | + detailVisible: false, | |
| 117 | + detail: '', | |
| 118 | + filterList: [], | |
| 119 | + }, | |
| 120 | + ], | |
| 121 | + clearRule: [], | |
| 217 | 122 | }); |
| 218 | 123 | }; |
| 219 | - const handleDeleteAlarm = (index) => { | |
| 220 | - alarmList.value.splice(index, 1); | |
| 221 | - }; | |
| 222 | - // 添加创建条件 | |
| 223 | - const addCreateRole = (index) => { | |
| 224 | - alarmList.value[index].alarmRule.push({ | |
| 124 | + | |
| 125 | + // 表单部分 报警类型 | |
| 126 | + const [registerForm] = useForm({ | |
| 127 | + labelWidth: 120, | |
| 128 | + schemas: step3Schemas, | |
| 129 | + showResetButton: false, | |
| 130 | + showSubmitButton: false, | |
| 131 | + }); | |
| 132 | + | |
| 133 | + // 高级设置 | |
| 134 | + const [registerFormHighSetting] = useForm({ | |
| 135 | + labelWidth: 120, | |
| 136 | + schemas: step3HighSetting, | |
| 137 | + showResetButton: false, | |
| 138 | + showSubmitButton: false, | |
| 139 | + actionColOptions: { | |
| 140 | + span: 24, | |
| 141 | + }, | |
| 142 | + }); | |
| 143 | + | |
| 144 | + // 添加创建条件表单 | |
| 145 | + const [registerFormCreateAlarm] = useForm({ | |
| 146 | + labelWidth: 120, | |
| 147 | + schemas: step3CreateAlarm, | |
| 148 | + showResetButton: false, | |
| 149 | + showSubmitButton: false, | |
| 150 | + actionColOptions: { | |
| 151 | + span: 24, | |
| 152 | + }, | |
| 153 | + }); | |
| 154 | + | |
| 155 | + // 清除条件表单 | |
| 156 | + const [registerFormClearAlarm] = useForm({ | |
| 157 | + labelWidth: 120, | |
| 158 | + schemas: step3ClearAlarm, | |
| 159 | + showResetButton: false, | |
| 160 | + showSubmitButton: false, | |
| 161 | + actionColOptions: { | |
| 162 | + span: 24, | |
| 163 | + }, | |
| 164 | + }); | |
| 165 | + | |
| 166 | + // 添加‘创建条件’ | |
| 167 | + const addCreateRole = (index: number) => { | |
| 168 | + unref(alarmList)[index].createRule.push({ | |
| 169 | + id: Date.now() + Math.random(), | |
| 170 | + alarmVisible: false, | |
| 171 | + addKeyFilterVisible: false, | |
| 172 | + detailVisible: false, | |
| 225 | 173 | detail: '', |
| 174 | + filterList: [], | |
| 226 | 175 | }); |
| 227 | 176 | }; |
| 228 | - const handleDeleteCondition = (index, index1) => { | |
| 229 | - alarmList.value[index].alarmRule.splice(index1, 1); | |
| 230 | - }; | |
| 231 | - | |
| 232 | - // 清除报警规则 | |
| 233 | - const addRemoveRule = (index) => { | |
| 234 | - alarmList.value[index].removeRule.push('1'); | |
| 235 | - }; | |
| 236 | - const handleDeleteRemoveCondition = (index, index1) => { | |
| 237 | - alarmList.value[index].removeRule.splice(index1, 1); | |
| 177 | + // 删除‘创建条件’ | |
| 178 | + const deleteCondition = (index: number, createIndex: number) => { | |
| 179 | + alarmList.value[index].createRule.splice(createIndex, 1); | |
| 238 | 180 | }; |
| 239 | - | |
| 240 | - // 编辑创建规则的详情 | |
| 241 | - const editCreateDetail = (index, index1) => { | |
| 242 | - visible.value = true; | |
| 243 | - console.log(alarmList.value[index].alarmRule[index1].detail); | |
| 244 | - }; | |
| 245 | - | |
| 246 | 181 | return { |
| 247 | - rules, | |
| 248 | 182 | alarmList, |
| 249 | - options, | |
| 250 | - visible, | |
| 183 | + deleteAlarmRule, | |
| 251 | 184 | prevStep, |
| 252 | 185 | addAlarmRule, |
| 186 | + | |
| 187 | + registerForm, | |
| 188 | + | |
| 189 | + registerFormHighSetting, | |
| 190 | + | |
| 191 | + registerFormCreateAlarm, | |
| 253 | 192 | addCreateRole, |
| 254 | - handleDeleteAlarm, | |
| 255 | - handleDeleteCondition, | |
| 256 | - addRemoveRule, | |
| 257 | - handleDeleteRemoveCondition, | |
| 258 | - editCreateDetail, | |
| 259 | - labelCol: { style: { width: '150px' } }, | |
| 260 | - wrapperCol: { span: 18 }, | |
| 193 | + deleteCondition, | |
| 194 | + | |
| 195 | + registerFormClearAlarm, | |
| 261 | 196 | }; |
| 262 | 197 | }, |
| 263 | 198 | }); |
| 264 | 199 | </script> |
| 200 | + | |
| 265 | 201 | <style lang="less" scoped> |
| 266 | 202 | .step3 { |
| 267 | - width: 500px; | |
| 268 | - margin: 0 auto; | |
| 203 | + width: 100%; | |
| 269 | 204 | } |
| 270 | - .alarm-rule { | |
| 271 | - height: 200px; | |
| 205 | + .border { | |
| 206 | + border: 1px solid #bfbfbf; | |
| 207 | + } | |
| 208 | + | |
| 209 | + .aic { | |
| 272 | 210 | display: flex; |
| 273 | - .alarm-remove { | |
| 274 | - display: flex; | |
| 275 | - justify-content: center; | |
| 276 | - align-items: center; | |
| 277 | - } | |
| 211 | + align-items: center; | |
| 212 | + } | |
| 213 | + | |
| 214 | + :deep(.vben-collapse-container__header) { | |
| 215 | + border: none; | |
| 278 | 216 | } |
| 279 | 217 | </style> | ... | ... |
| 1 | +<template> | |
| 2 | + <div class="step3"> | |
| 3 | + <h1 v-if="alarmList.length === 0" style="font-size: 24px" class="text-center" | |
| 4 | + >未配置报警规则</h1 | |
| 5 | + > | |
| 6 | + | |
| 7 | + <template v-else v-for="(item, index) in alarmList" :key="item"> | |
| 8 | + <CollapseContainer :title="item.alarmType" style="border: 1px solid #bfbfbf" class="mb-6"> | |
| 9 | + <template #action> | |
| 10 | + <div @click="handleDeleteAlarm(index)" class="cursor-pointer"> | |
| 11 | + <DeleteOutlined style="font-size: 20px" class="mr-2" /> | |
| 12 | + </div> | |
| 13 | + </template> | |
| 14 | + <a-form :wrapper-col="wrapperCol" labelAlign="left" :model="item" :rules="rules"> | |
| 15 | + <a-form-item label="报警类型" :labelCol="{ style: { width: '80px' } }" name="alarmType"> | |
| 16 | + <a-input v-model:value="item.alarmType" /> | |
| 17 | + </a-form-item> | |
| 18 | + </a-form> | |
| 19 | + | |
| 20 | + <CollapseContainer> | |
| 21 | + <template #action> 高级设置 </template> | |
| 22 | + <div class="flex" style="align-items: center"> | |
| 23 | + <input type="checkbox" v-model="item.isPass" /> <div class="ml-2">传递警报</div> | |
| 24 | + </div> | |
| 25 | + | |
| 26 | + <a-form :wrapper-col="wrapperCol" labelAlign="left" v-if="item.isPass"> | |
| 27 | + <a-form-item label="传递的关联类型" :labelCol="{ style: { width: '120px' } }"> | |
| 28 | + <a-input /> | |
| 29 | + </a-form-item> | |
| 30 | + </a-form> | |
| 31 | + </CollapseContainer> | |
| 32 | + <p style="color: #3c3c3c">创建报警规则</p> | |
| 33 | + <template v-for="(item1, index1) in item.alarmRule" :key="item1"> | |
| 34 | + <div class="alarm-rule mb-4"> | |
| 35 | + <div style="width: 90%; border: 2px solid #8c8c8c; border-radius: 5px" class="flex"> | |
| 36 | + <div style="width: 30%; height: 100%; border-right: 1px solid #e0e0e0"> | |
| 37 | + <span style="color: #305680; margin-left: 10px">严重程度</span> | |
| 38 | + <a-select :options="options" style="width: 100px; margin-left: 10px" /> | |
| 39 | + </div> | |
| 40 | + <div style="width: 70%; height: 100%"> | |
| 41 | + <p style="color: #f5594e" class="mt-4 ml-4" | |
| 42 | + >请添加报警规则条件 | |
| 43 | + <PlusOutlined | |
| 44 | + class="cursor-pointer ml-4" | |
| 45 | + style="font-size: 20px" | |
| 46 | + @click="editAlarmCondition(index, index1)" | |
| 47 | + /></p> | |
| 48 | + <p class="mt-4 ml-4" | |
| 49 | + >启用规则:始终启用 | |
| 50 | + <EditOutlined class="cursor-pointer ml-4" style="font-size: 20px" | |
| 51 | + /></p> | |
| 52 | + <p class="mt-4 ml-4" | |
| 53 | + >详情:{{ item1.detail }} | |
| 54 | + <EditOutlined | |
| 55 | + @click="item1.detailVisible = true" | |
| 56 | + class="cursor-pointer ml-4" | |
| 57 | + style="font-size: 20px" | |
| 58 | + /></p> | |
| 59 | + <p class="mt-4 ml-4">dashboard: <a-select style="width: 180px" /></p> | |
| 60 | + </div> | |
| 61 | + </div> | |
| 62 | + <div style="width: 10%" class="alarm-remove"> | |
| 63 | + <a-tooltip title="移除"> | |
| 64 | + <MinusCircleOutlined | |
| 65 | + style="font-size: 25px color:#305680" | |
| 66 | + class="cursor-pointer" | |
| 67 | + @click="handleDeleteCondition(index, index1)" | |
| 68 | + /> | |
| 69 | + </a-tooltip> | |
| 70 | + </div> | |
| 71 | + </div> | |
| 72 | + <!-- 编辑报警规则条件 --> | |
| 73 | + <a-modal | |
| 74 | + v-model:visible="item1.alarmVisible" | |
| 75 | + title="编辑报警规则条件" | |
| 76 | + centered | |
| 77 | + width="800px" | |
| 78 | + @cancel="handleAlarmCancel(index, index1)" | |
| 79 | + @ok="item1.alarmVisible = false" | |
| 80 | + > | |
| 81 | + <CollapseContainer title="键名筛选器" style="border: 1px solid #bfbfbf" class="mb-6"> | |
| 82 | + <a-modal | |
| 83 | + v-model:visible="item1.addKeyFilterVisible" | |
| 84 | + title="添加键名筛选器" | |
| 85 | + centered | |
| 86 | + width="600px" | |
| 87 | + @ok="item1.addKeyFilterVisible = false" | |
| 88 | + > | |
| 89 | + <a-form | |
| 90 | + :wrapper-col="wrapperCol" | |
| 91 | + :labelCol="{ style: { width: '80px' } }" | |
| 92 | + labelAlign="right" | |
| 93 | + > | |
| 94 | + <a-form-item label="键类型"> | |
| 95 | + <a-select :options="keyTypeOptions" default-value="Timeseries" /> | |
| 96 | + </a-form-item> | |
| 97 | + <a-form-item label="键名"> | |
| 98 | + <a-input /> | |
| 99 | + </a-form-item> | |
| 100 | + <a-form-item label="值类型"> | |
| 101 | + <a-select :options="valueTypeOptions" /> | |
| 102 | + </a-form-item> | |
| 103 | + </a-form> | |
| 104 | + <collapseContainer title="筛选器"> | |
| 105 | + <template v-for="filterItem in item1.filterList" :key="filterItem"> | |
| 106 | + <div class="flex justify-between mb-4" style="align-items: center"> | |
| 107 | + <a-select | |
| 108 | + style="width: 150px" | |
| 109 | + :options="operatorOptions" | |
| 110 | + default-value="=" | |
| 111 | + /><a-input style="width: 350px" /> | |
| 112 | + <a-tooltip title="删除筛选器"> | |
| 113 | + <CloseOutlined @click="deleteFilter(index, index1)" /> | |
| 114 | + </a-tooltip> | |
| 115 | + </div> | |
| 116 | + </template> | |
| 117 | + <div class="flex"> | |
| 118 | + <a-button type="primary" class="mr-4" @click="addFilter(index, index1)" | |
| 119 | + >添加</a-button | |
| 120 | + > | |
| 121 | + <a-button type="primary">添加复合</a-button> | |
| 122 | + </div> | |
| 123 | + </collapseContainer> | |
| 124 | + </a-modal> | |
| 125 | + <div class="flex justify-start"> | |
| 126 | + <a-button type="primary" @click="item1.addKeyFilterVisible = true" | |
| 127 | + >添加键名筛选器</a-button | |
| 128 | + > | |
| 129 | + </div> | |
| 130 | + </CollapseContainer> | |
| 131 | + <CollapseContainer title="筛选器预览" style="border: 1px solid #bfbfbf" class="mb-6" /> | |
| 132 | + </a-modal> | |
| 133 | + <!-- 启用规则--> | |
| 134 | + <!-- <a-modal | |
| 135 | + v-model:visible="visible" | |
| 136 | + title="编辑报警规则条件" | |
| 137 | + centered | |
| 138 | + @cancel="handleCancel(index, index1)" | |
| 139 | + @ok="visible = false" | |
| 140 | + > | |
| 141 | + 编辑报警规则条件123 | |
| 142 | + </a-modal> --> | |
| 143 | + | |
| 144 | + <!-- 创建报警规则详情的弹框 --> | |
| 145 | + <a-modal | |
| 146 | + v-model:visible="item1.detailVisible" | |
| 147 | + title="详情" | |
| 148 | + centered | |
| 149 | + @cancel="handleCancel(index, index1)" | |
| 150 | + @ok="item1.detailVisible = false" | |
| 151 | + > | |
| 152 | + <a-textarea v-model:value="item1.detail" placeholder="报警详细信息" :rows="4" /> | |
| 153 | + </a-modal> | |
| 154 | + </template> | |
| 155 | + <a-button class="mt-5" @click="addCreateRole(index)" | |
| 156 | + ><PlusCircleOutlined />添加创建条件</a-button | |
| 157 | + > | |
| 158 | + <p style="color: #3c3c3c">清除报警规则</p> | |
| 159 | + <template v-for="(item2, index2) in item.removeRule" :key="item2"> | |
| 160 | + <div class="alarm-rule mb-4"> | |
| 161 | + <div style="width: 90%; border: 2px solid #8c8c8c; border-radius: 5px" class="flex"> | |
| 162 | + <div style="width: 70%; height: 100%"> | |
| 163 | + <p style="color: #f5594e" class="mt-4 ml-4" | |
| 164 | + >请添加报警规则条件 | |
| 165 | + <PlusOutlined class="cursor-pointer ml-4" style="font-size: 20px" | |
| 166 | + /></p> | |
| 167 | + <p class="mt-4 ml-4" | |
| 168 | + >启用规则:始终启用 | |
| 169 | + <EditOutlined class="cursor-pointer ml-4" style="font-size: 20px" | |
| 170 | + /></p> | |
| 171 | + <p class="mt-4 ml-4" | |
| 172 | + >详情:{{ item2.detail }} | |
| 173 | + <EditOutlined | |
| 174 | + class="cursor-pointer ml-4" | |
| 175 | + style="font-size: 20px" | |
| 176 | + @click="editRemoveVisible = true" | |
| 177 | + /> | |
| 178 | + </p> | |
| 179 | + | |
| 180 | + <p class="mt-4 ml-4">Mobile dashboard: <a-select style="width: 150px" /></p> | |
| 181 | + </div> | |
| 182 | + </div> | |
| 183 | + <div style="width: 10%" class="alarm-remove"> | |
| 184 | + <a-tooltip title="移除"> | |
| 185 | + <MinusCircleOutlined | |
| 186 | + style="font-size: 25px color:#305680" | |
| 187 | + class="cursor-pointer" | |
| 188 | + @click="handleDeleteRemoveCondition(index, index2)" | |
| 189 | + /> | |
| 190 | + </a-tooltip> | |
| 191 | + </div> | |
| 192 | + </div> | |
| 193 | + <a-modal | |
| 194 | + v-model:visible="editRemoveVisible" | |
| 195 | + title="详情" | |
| 196 | + centered | |
| 197 | + @cancel="handleCancel1(index, index2)" | |
| 198 | + @ok="editRemoveVisible = false" | |
| 199 | + > | |
| 200 | + <a-textarea v-model:value="item2.detail" placeholder="报警详细信息" :rows="4" /> | |
| 201 | + </a-modal> | |
| 202 | + </template> | |
| 203 | + <a-button class="mt-5" @click="addRemoveRule(index)" | |
| 204 | + ><PlusCircleOutlined />添加清除条件</a-button | |
| 205 | + > | |
| 206 | + </CollapseContainer> | |
| 207 | + </template> | |
| 208 | + <div class="flex justify-start"> | |
| 209 | + <a-button class="mr-5" @click="prevStep">上一步</a-button> | |
| 210 | + <a-button type="primary" @click="addAlarmRule">添加报警规则</a-button> | |
| 211 | + </div> | |
| 212 | + </div> | |
| 213 | +</template> | |
| 214 | +<script lang="ts"> | |
| 215 | + import { defineComponent, ref } from 'vue'; | |
| 216 | + import { | |
| 217 | + Alert, | |
| 218 | + Divider, | |
| 219 | + Descriptions, | |
| 220 | + Input, | |
| 221 | + Form, | |
| 222 | + FormItem, | |
| 223 | + Button, | |
| 224 | + Select, | |
| 225 | + Tooltip, | |
| 226 | + Textarea, | |
| 227 | + Modal, | |
| 228 | + } from 'ant-design-vue'; | |
| 229 | + import { | |
| 230 | + DeleteOutlined, | |
| 231 | + MinusCircleOutlined, | |
| 232 | + PlusCircleOutlined, | |
| 233 | + PlusOutlined, | |
| 234 | + EditOutlined, | |
| 235 | + CloseOutlined, | |
| 236 | + } from '@ant-design/icons-vue'; | |
| 237 | + import { CollapseContainer } from '/@/components/Container/index'; | |
| 238 | + import { alarmListItem } from '../types/index'; | |
| 239 | + export default defineComponent({ | |
| 240 | + components: { | |
| 241 | + DeleteOutlined, | |
| 242 | + MinusCircleOutlined, | |
| 243 | + PlusCircleOutlined, | |
| 244 | + CollapseContainer, | |
| 245 | + EditOutlined, | |
| 246 | + PlusOutlined, | |
| 247 | + CloseOutlined, | |
| 248 | + [Form.name]: Form, | |
| 249 | + [FormItem.name]: FormItem, | |
| 250 | + [Modal.name]: Modal, | |
| 251 | + [Textarea.name]: Textarea, | |
| 252 | + [Tooltip.name]: Tooltip, | |
| 253 | + [Button.name]: Button, | |
| 254 | + [Input.name]: Input, | |
| 255 | + [Select.name]: Select, | |
| 256 | + [Form.name]: Form, | |
| 257 | + [Form.Item.name]: Form.Item, | |
| 258 | + [Alert.name]: Alert, | |
| 259 | + [Divider.name]: Divider, | |
| 260 | + [Descriptions.name]: Descriptions, | |
| 261 | + [Descriptions.Item.name]: Descriptions.Item, | |
| 262 | + }, | |
| 263 | + emits: ['prev'], | |
| 264 | + setup(_, { emit }) { | |
| 265 | + const alarmList = ref<alarmListItem[]>([]); | |
| 266 | + | |
| 267 | + const options = ref([ | |
| 268 | + { | |
| 269 | + value: '1', | |
| 270 | + label: '危险', | |
| 271 | + }, | |
| 272 | + | |
| 273 | + { | |
| 274 | + value: '2', | |
| 275 | + label: '重要', | |
| 276 | + }, | |
| 277 | + { | |
| 278 | + value: '3', | |
| 279 | + label: '次要', | |
| 280 | + }, | |
| 281 | + { | |
| 282 | + value: '4', | |
| 283 | + label: '警告', | |
| 284 | + }, | |
| 285 | + { | |
| 286 | + value: '5', | |
| 287 | + label: '不确定', | |
| 288 | + }, | |
| 289 | + ]); | |
| 290 | + const keyTypeOptions = ref([ | |
| 291 | + { | |
| 292 | + value: 'properties', | |
| 293 | + label: '属性', | |
| 294 | + }, | |
| 295 | + | |
| 296 | + { | |
| 297 | + value: 'Timeseries', | |
| 298 | + label: 'Timeseries', | |
| 299 | + }, | |
| 300 | + { | |
| 301 | + value: 'constant', | |
| 302 | + label: '常量', | |
| 303 | + }, | |
| 304 | + ]); | |
| 305 | + const valueTypeOptions = ref([ | |
| 306 | + { | |
| 307 | + value: 'string', | |
| 308 | + label: '字符串', | |
| 309 | + }, | |
| 310 | + { | |
| 311 | + value: 'number', | |
| 312 | + label: '数字', | |
| 313 | + }, | |
| 314 | + { | |
| 315 | + value: 'boolean', | |
| 316 | + label: '布尔值', | |
| 317 | + }, | |
| 318 | + { | |
| 319 | + value: 'dateTime', | |
| 320 | + label: '日期时间', | |
| 321 | + }, | |
| 322 | + ]); | |
| 323 | + const operatorOptions = ref([ | |
| 324 | + { | |
| 325 | + value: '=', | |
| 326 | + label: '等于', | |
| 327 | + }, | |
| 328 | + { | |
| 329 | + value: '!=', | |
| 330 | + label: '不等于', | |
| 331 | + }, | |
| 332 | + { | |
| 333 | + value: '>', | |
| 334 | + label: '大于', | |
| 335 | + }, | |
| 336 | + { | |
| 337 | + value: '<', | |
| 338 | + label: '小于', | |
| 339 | + }, | |
| 340 | + { | |
| 341 | + value: '>=', | |
| 342 | + label: '大于或等于', | |
| 343 | + }, | |
| 344 | + { | |
| 345 | + value: '<=', | |
| 346 | + label: '小于或等于', | |
| 347 | + }, | |
| 348 | + ]); | |
| 349 | + const rules = { | |
| 350 | + alarmType: [ | |
| 351 | + { | |
| 352 | + required: true, | |
| 353 | + message: '报警类型必填', | |
| 354 | + trigger: 'blur', | |
| 355 | + }, | |
| 356 | + ], | |
| 357 | + }; | |
| 358 | + | |
| 359 | + const prevStep = () => { | |
| 360 | + emit('prev'); | |
| 361 | + }; | |
| 362 | + // 添加报警规则 | |
| 363 | + const addAlarmRule = () => { | |
| 364 | + alarmList.value.push({ | |
| 365 | + alarmType: '', | |
| 366 | + isPass: false, | |
| 367 | + createRule: [], | |
| 368 | + clearRule: [], | |
| 369 | + }); | |
| 370 | + }; | |
| 371 | + const handleDeleteAlarm = (index: number) => { | |
| 372 | + alarmList.value.splice(index, 1); | |
| 373 | + }; | |
| 374 | + // 添加‘创建条件’ | |
| 375 | + const addCreateRole = (index: number) => { | |
| 376 | + alarmList.value[index].createRule.push({ | |
| 377 | + alarmVisible: false, | |
| 378 | + addKeyFilterVisible: false, | |
| 379 | + detailVisible: false, | |
| 380 | + detail: '', | |
| 381 | + filterList: [], | |
| 382 | + }); | |
| 383 | + }; | |
| 384 | + const handleDeleteCondition = (index: number, index1: number) => { | |
| 385 | + alarmList.value[index].createRule.splice(index1, 1); | |
| 386 | + }; | |
| 387 | + | |
| 388 | + // 添加‘清除报警规则’ | |
| 389 | + const addRemoveRule = (index: number) => { | |
| 390 | + alarmList.value[index].clearRule.push({ | |
| 391 | + detail: '', | |
| 392 | + }); | |
| 393 | + }; | |
| 394 | + const handleDeleteRemoveCondition = (index: number, index1: number) => { | |
| 395 | + alarmList.value[index].clearRule.splice(index1, 1); | |
| 396 | + }; | |
| 397 | + | |
| 398 | + // 弹框取消事件 --2个 | |
| 399 | + const visible = ref(false); | |
| 400 | + const editRemoveVisible = ref(false); | |
| 401 | + const handleCancel = (index: number, index1: number) => { | |
| 402 | + alarmList.value[index].createRule[index1].detail = ''; | |
| 403 | + alarmList.value[index].createRule[index1].detailVisible = false; | |
| 404 | + }; | |
| 405 | + | |
| 406 | + const handleCancel1 = (index: number, index2: number) => { | |
| 407 | + alarmList.value[index].clearRule[index2].detail = ''; | |
| 408 | + editRemoveVisible.value = false; | |
| 409 | + }; | |
| 410 | + | |
| 411 | + const handleAlarmCancel = (index, index1) => { | |
| 412 | + alarmList.value[index].createRule[index1].alarmVisible = false; | |
| 413 | + console.log('object---'); | |
| 414 | + }; | |
| 415 | + const editAlarmCondition = (index, index1) => { | |
| 416 | + alarmList.value[index].createRule[index1].alarmVisible = true; | |
| 417 | + console.log('object'); | |
| 418 | + }; | |
| 419 | + // 添加键名筛选器 | |
| 420 | + const addFilter = (index, index1) => { | |
| 421 | + console.log(index, index1); | |
| 422 | + alarmList.value[index].createRule[index1].filterList?.push({ | |
| 423 | + operator: '=', | |
| 424 | + value: '', | |
| 425 | + }); | |
| 426 | + }; | |
| 427 | + const deleteFilter = (index: number, index1: number) => { | |
| 428 | + alarmList.value[index].createRule[index1].filterList?.splice(index1, 1); | |
| 429 | + }; | |
| 430 | + return { | |
| 431 | + rules, | |
| 432 | + alarmList, | |
| 433 | + options, | |
| 434 | + visible, | |
| 435 | + editRemoveVisible, | |
| 436 | + prevStep, | |
| 437 | + addAlarmRule, | |
| 438 | + addCreateRole, | |
| 439 | + handleDeleteAlarm, | |
| 440 | + handleDeleteCondition, | |
| 441 | + addRemoveRule, | |
| 442 | + handleDeleteRemoveCondition, | |
| 443 | + handleCancel, | |
| 444 | + handleCancel1, | |
| 445 | + handleAlarmCancel, | |
| 446 | + editAlarmCondition, | |
| 447 | + keyTypeOptions, | |
| 448 | + valueTypeOptions, | |
| 449 | + operatorOptions, | |
| 450 | + deleteFilter, | |
| 451 | + addFilter, | |
| 452 | + labelCol: { style: { width: '150px' } }, | |
| 453 | + wrapperCol: { span: 18 }, | |
| 454 | + }; | |
| 455 | + }, | |
| 456 | + }); | |
| 457 | +</script> | |
| 458 | +<style lang="less" scoped> | |
| 459 | + .step3 { | |
| 460 | + width: 500px; | |
| 461 | + margin: 0 auto; | |
| 462 | + } | |
| 463 | + .alarm-rule { | |
| 464 | + height: 200px; | |
| 465 | + display: flex; | |
| 466 | + .alarm-remove { | |
| 467 | + display: flex; | |
| 468 | + justify-content: center; | |
| 469 | + align-items: center; | |
| 470 | + } | |
| 471 | + } | |
| 472 | +</style> | ... | ... |
| ... | ... | @@ -46,11 +46,73 @@ export const step2Schemas: FormSchema[] = [ |
| 46 | 46 | export const step3Schemas: FormSchema[] = [ |
| 47 | 47 | { |
| 48 | 48 | field: 'transportType', |
| 49 | + component: 'Input', | |
| 50 | + label: '报警类型', | |
| 51 | + required: true, | |
| 52 | + componentProps: { | |
| 53 | + placeholder: '请输入报警类型', | |
| 54 | + }, | |
| 55 | + }, | |
| 56 | +]; | |
| 57 | + | |
| 58 | +export const step3HighSetting: FormSchema[] = [ | |
| 59 | + { | |
| 60 | + field: 'isPass', | |
| 61 | + component: 'Checkbox', | |
| 62 | + label: '', | |
| 63 | + slot: 'checkBox', | |
| 64 | + }, | |
| 65 | + { | |
| 66 | + field: 'associationType', | |
| 67 | + component: 'Input', | |
| 68 | + label: '关联类型', | |
| 69 | + componentProps: { | |
| 70 | + placeholder: '要传递的关联类型', | |
| 71 | + }, | |
| 72 | + ifShow: ({ values }) => !!values.isPass, | |
| 73 | + }, | |
| 74 | +]; | |
| 75 | + | |
| 76 | +export const step3CreateAlarm: FormSchema[] = [ | |
| 77 | + { | |
| 78 | + field: 'severity', | |
| 49 | 79 | component: 'Select', |
| 50 | - label: '报警规则', | |
| 51 | - defaultValue: 'DEFAULT', | |
| 80 | + label: '严重程度', | |
| 52 | 81 | componentProps: { |
| 53 | - options: [{ label: '默认', value: 'DEFAULT' }], | |
| 82 | + placeholder: '请选择严重程度', | |
| 83 | + options: [ | |
| 84 | + { | |
| 85 | + value: '1', | |
| 86 | + label: '危险', | |
| 87 | + }, | |
| 88 | + { | |
| 89 | + value: '2', | |
| 90 | + label: '重要', | |
| 91 | + }, | |
| 92 | + { | |
| 93 | + value: '3', | |
| 94 | + label: '次要', | |
| 95 | + }, | |
| 96 | + { | |
| 97 | + value: '4', | |
| 98 | + label: '警告', | |
| 99 | + }, | |
| 100 | + { | |
| 101 | + value: '5', | |
| 102 | + label: '不确定', | |
| 103 | + }, | |
| 104 | + ], | |
| 54 | 105 | }, |
| 55 | 106 | }, |
| 56 | 107 | ]; |
| 108 | + | |
| 109 | +export const step3ClearAlarm: FormSchema[] = [ | |
| 110 | + // { | |
| 111 | + // field: 'associationType', | |
| 112 | + // component: 'Input', | |
| 113 | + // label: '关联类型', | |
| 114 | + // componentProps: { | |
| 115 | + // placeholder: '要传递的关联类型', | |
| 116 | + // }, | |
| 117 | + // }, | |
| 118 | +]; | ... | ... |
src/views/device/profile/types/index.ts
0 → 100644
| 1 | +interface alarmRuleFilter { | |
| 2 | + operator: string; | |
| 3 | + value: string; | |
| 4 | +} | |
| 5 | +interface createRule { | |
| 6 | + id: number; | |
| 7 | + alarmVisible: boolean; | |
| 8 | + addKeyFilterVisible: boolean; | |
| 9 | + detailVisible: boolean; | |
| 10 | + detail: string; | |
| 11 | + filterList?: alarmRuleFilter[]; | |
| 12 | +} | |
| 13 | +interface clearRule { | |
| 14 | + detail: string; | |
| 15 | +} | |
| 16 | +export interface alarmListItem { | |
| 17 | + id: number; | |
| 18 | + alarmType: string; | |
| 19 | + isPass: boolean; | |
| 20 | + createRule: createRule[]; | |
| 21 | + clearRule: clearRule[]; | |
| 22 | +} | ... | ... |
| 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
| 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 | +} | ... | ... |