Commit c483fa56ff52829bcb5c9bdfeb8ebfddab2f05b2
Merge branch 'perf/main_dev' into 'main_dev'
perf: 优化告警列表组件,少于十条数据时不滚动 See merge request yunteng/thingskit-scada!162
Showing
11 changed files
with
71 additions
and
41 deletions
| @@ -110,7 +110,7 @@ | @@ -110,7 +110,7 @@ | ||
| 110 | fill: none; | 110 | fill: none; |
| 111 | stroke: white; | 111 | stroke: white; |
| 112 | stroke-dasharray: 6% 29%; | 112 | stroke-dasharray: 6% 29%; |
| 113 | - stroke-width: 5px; | 113 | + stroke-width: 3px; |
| 114 | stroke-dashoffset: 0%; | 114 | stroke-dashoffset: 0%; |
| 115 | animation: stroke-offset 5.5s infinite linear; | 115 | animation: stroke-offset 5.5s infinite linear; |
| 116 | } | 116 | } |
| 1 | import type { DeviceAttributeItemType, DeviceItemType, DeviceProfileItemType, OrganizationItemType, RpcCommandType, SendValue, ThingsModel, ThingsModelItemType } from './model' | 1 | import type { DeviceAttributeItemType, DeviceItemType, DeviceProfileItemType, OrganizationItemType, RpcCommandType, SendValue, ThingsModel, ThingsModelItemType } from './model' |
| 2 | -import type { CommandWayEnum } from '@/enums/commandEnum' | 2 | +import { CommandWayEnum } from '@/enums/commandEnum' |
| 3 | import type { DeviceTypeEnum } from '@/enums/datasource' | 3 | import type { DeviceTypeEnum } from '@/enums/datasource' |
| 4 | import { isShareMode } from '@/utils/env' | 4 | import { isShareMode } from '@/utils/env' |
| 5 | import { defHttp } from '@/utils/http' | 5 | import { defHttp } from '@/utils/http' |
| @@ -15,6 +15,7 @@ enum Api { | @@ -15,6 +15,7 @@ enum Api { | ||
| 15 | RPC_COMMAND = '/rpc/', | 15 | RPC_COMMAND = '/rpc/', |
| 16 | GET_DEVICE_ACTIVE = 'plugins/telemetry/DEVICE/', | 16 | GET_DEVICE_ACTIVE = 'plugins/telemetry/DEVICE/', |
| 17 | RPC_ONEWAY = '/rpc/oneway', | 17 | RPC_ONEWAY = '/rpc/oneway', |
| 18 | + RPC_TWOWAY = '/rpc/twoway', | ||
| 18 | 19 | ||
| 19 | GEN_MODBUS_COMMAND = '/js/modbus', | 20 | GEN_MODBUS_COMMAND = '/js/modbus', |
| 20 | GET_DEVICE_DETAIL = '/device/', // 获取设备详情 | 21 | GET_DEVICE_DETAIL = '/device/', // 获取设备详情 |
| @@ -88,9 +89,9 @@ export const getDeviceActive = (deviceId: string) => { | @@ -88,9 +89,9 @@ export const getDeviceActive = (deviceId: string) => { | ||
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | // 命令下发 | 91 | // 命令下发 |
| 91 | -export const sendRpcOneway = (param: SendValue | any, deviceId?: string) => { | 92 | +export const sendRpcOneway = (param: SendValue | any, deviceId?: string, way?: string) => { |
| 92 | return defHttp.post({ | 93 | return defHttp.post({ |
| 93 | - url: `${Api.RPC_ONEWAY}/${deviceId}`, | 94 | + url: `${way !== CommandWayEnum.TWO_WAY ? Api.RPC_ONEWAY : Api.RPC_TWOWAY}/${deviceId}`, |
| 94 | data: param, | 95 | data: param, |
| 95 | }, | 96 | }, |
| 96 | { | 97 | { |
| @@ -161,11 +161,13 @@ export interface RangeItemType { | @@ -161,11 +161,13 @@ export interface RangeItemType { | ||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | export interface BasicActDataType { | 163 | export interface BasicActDataType { |
| 164 | - deviceId: string | ||
| 165 | - attr: string | 164 | + deviceId?: string |
| 165 | + attr?: string | ||
| 166 | enable?: boolean | 166 | enable?: boolean |
| 167 | deviceProfileId?: string | number | 167 | deviceProfileId?: string | number |
| 168 | + deviceProfileTemplateId?: string | number | ||
| 168 | attrInfo?: ThingsModelItemType | 169 | attrInfo?: ThingsModelItemType |
| 170 | + deviceInfo?: DeviceTypeEnum | ||
| 169 | } | 171 | } |
| 170 | 172 | ||
| 171 | export interface FlashActDataType extends BasicActDataType { | 173 | export interface FlashActDataType extends BasicActDataType { |
| @@ -53,9 +53,9 @@ const getTitle = computed(() => { | @@ -53,9 +53,9 @@ const getTitle = computed(() => { | ||
| 53 | </p> | 53 | </p> |
| 54 | </div> | 54 | </div> |
| 55 | </template> | 55 | </template> |
| 56 | - <span :class="prefixCls"> | 56 | + <span :class="prefixCls" class="flex items-center"> |
| 57 | <component :is="slot as RendererElement" v-if="slots?.default" /> | 57 | <component :is="slot as RendererElement" v-if="slots?.default" /> |
| 58 | - <Icon v-if="!slots?.default" icon="ph:question" class="svg:text-base" /> | 58 | + <Icon v-if="!slots?.default" icon="ph:question" class="cursor-pointer text-base" /> |
| 59 | </span> | 59 | </span> |
| 60 | </Tooltip> | 60 | </Tooltip> |
| 61 | </template> | 61 | </template> |
| @@ -253,7 +253,7 @@ export default defineComponent({ | @@ -253,7 +253,7 @@ export default defineComponent({ | ||
| 253 | return renderLabel | 253 | return renderLabel |
| 254 | 254 | ||
| 255 | return ( | 255 | return ( |
| 256 | - <span> | 256 | + <span class='flex items-center'> |
| 257 | {renderLabel} | 257 | {renderLabel} |
| 258 | <BasicHelp placement="top" class="mx-1" text={getHelpMessage} {...helpComponentProps} /> | 258 | <BasicHelp placement="top" class="mx-1" text={getHelpMessage} {...helpComponentProps} /> |
| 259 | </span> | 259 | </span> |
| @@ -79,7 +79,6 @@ const handleDeleteRow = (data: FlashActDataType) => { | @@ -79,7 +79,6 @@ const handleDeleteRow = (data: FlashActDataType) => { | ||
| 79 | 79 | ||
| 80 | const getFieldsValue = () => { | 80 | const getFieldsValue = () => { |
| 81 | const values = getFieldsForm() | 81 | const values = getFieldsForm() |
| 82 | - const { deviceId, attr, deviceProfileId, attrInfo } = values | ||
| 83 | const rangeList = unref(dataSource).map((item) => { | 82 | const rangeList = unref(dataSource).map((item) => { |
| 84 | return { | 83 | return { |
| 85 | ...item, | 84 | ...item, |
| @@ -87,17 +86,14 @@ const getFieldsValue = () => { | @@ -87,17 +86,14 @@ const getFieldsValue = () => { | ||
| 87 | } | 86 | } |
| 88 | }) | 87 | }) |
| 89 | return { | 88 | return { |
| 90 | - deviceId, | ||
| 91 | - attr, | ||
| 92 | - deviceProfileId, | ||
| 93 | - attrInfo, | 89 | + ...values, |
| 94 | rangeList, | 90 | rangeList, |
| 95 | } as BasicFlashActDataType | 91 | } as BasicFlashActDataType |
| 96 | } | 92 | } |
| 97 | 93 | ||
| 98 | const setFieldsValue = (list: FlashActDataType) => { | 94 | const setFieldsValue = (list: FlashActDataType) => { |
| 99 | - const { attr, deviceId, rangeList } = list || {} | ||
| 100 | - setFieldsForm({ attr, deviceId }) | 95 | + const { rangeList } = list || {} |
| 96 | + setFieldsForm(list || {}) | ||
| 101 | clearValidate() | 97 | clearValidate() |
| 102 | dataSource.value = rangeList ? rangeList?.map(item => ({ ...item, uuid: buildUUID() })) : [getInitTableRecord()] | 98 | dataSource.value = rangeList ? rangeList?.map(item => ({ ...item, uuid: buildUUID() })) : [getInitTableRecord()] |
| 103 | } | 99 | } |
src/core/Library/components/PublicForm/components/DataEffects/SetVariableImage/ImageSettingTable.vue
| @@ -128,3 +128,14 @@ defineExpose<ComponentExposeType>({ | @@ -128,3 +128,14 @@ defineExpose<ComponentExposeType>({ | ||
| 128 | </template> | 128 | </template> |
| 129 | </BasicTable> | 129 | </BasicTable> |
| 130 | </template> | 130 | </template> |
| 131 | + | ||
| 132 | +<style lang="less" scoped> | ||
| 133 | + .variable-image-form { | ||
| 134 | + >:deep(.ant-row) { | ||
| 135 | + >.ant-col { | ||
| 136 | + @apply px-4; | ||
| 137 | + } | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | +</style> | ||
| 141 | + |
| @@ -11,6 +11,7 @@ import { genModbusCommand, getDeviceActiveTime, getDeviceInfo, getThingsModelSer | @@ -11,6 +11,7 @@ import { genModbusCommand, getDeviceActiveTime, getDeviceInfo, getThingsModelSer | ||
| 11 | import { ThingsModelForm } from '@/core/Library/components/ThingsModelForm' | 11 | import { ThingsModelForm } from '@/core/Library/components/ThingsModelForm' |
| 12 | import { useMessage } from '@/hooks/web/useMessage' | 12 | import { useMessage } from '@/hooks/web/useMessage' |
| 13 | import type { StructJSON } from '@/api/device/model' | 13 | import type { StructJSON } from '@/api/device/model' |
| 14 | +import { CommandWayEnum } from '@/enums/commandEnum' | ||
| 14 | 15 | ||
| 15 | interface ServiceInfo { | 16 | interface ServiceInfo { |
| 16 | title?: string | 17 | title?: string |
| @@ -19,6 +20,7 @@ interface ServiceInfo { | @@ -19,6 +20,7 @@ interface ServiceInfo { | ||
| 19 | transportType?: string | 20 | transportType?: string |
| 20 | callType?: string | 21 | callType?: string |
| 21 | code?: string | 22 | code?: string |
| 23 | + way?: string | ||
| 22 | } | 24 | } |
| 23 | 25 | ||
| 24 | const visible = ref<boolean>(false) | 26 | const visible = ref<boolean>(false) |
| @@ -49,6 +51,7 @@ const serviceInfo = reactive<ServiceInfo>({ | @@ -49,6 +51,7 @@ const serviceInfo = reactive<ServiceInfo>({ | ||
| 49 | transportType: '', | 51 | transportType: '', |
| 50 | callType: '', | 52 | callType: '', |
| 51 | code: '', | 53 | code: '', |
| 54 | + way: '', // 单向还是双向 | ||
| 52 | }) | 55 | }) |
| 53 | 56 | ||
| 54 | const [register, { getFieldsValue, validate, setFieldsValue, updateSchema, setProps }] = useForm({ // 自定义下发值 | 57 | const [register, { getFieldsValue, validate, setFieldsValue, updateSchema, setProps }] = useForm({ // 自定义下发值 |
| @@ -88,11 +91,12 @@ const getDeviceDetail = async (deviceId: string) => { | @@ -88,11 +91,12 @@ const getDeviceDetail = async (deviceId: string) => { | ||
| 88 | } | 91 | } |
| 89 | 92 | ||
| 90 | const open = async (_data: SingleClickEventDataType) => { | 93 | const open = async (_data: SingleClickEventDataType) => { |
| 94 | + console.warn(_data, 'data') | ||
| 91 | const { operationPassword } = _data || {} | 95 | const { operationPassword } = _data || {} |
| 92 | dataSourceJson.value = _data.deviceInfo | 96 | dataSourceJson.value = _data.deviceInfo |
| 93 | isPasswordInfo.value = operationPassword || {} | 97 | isPasswordInfo.value = operationPassword || {} |
| 94 | // commandWay-->命令下发方式 | 98 | // commandWay-->命令下发方式 |
| 95 | - const { commandWay, customCommand, serviceCommand, service, callType } = _data || {} | 99 | + const { commandWay, customCommand, serviceCommand, service, callType, way } = _data || {} |
| 96 | isCommandWay.value = commandWay | 100 | isCommandWay.value = commandWay |
| 97 | const { attrInfo, deviceId } = unref(dataSourceJson) | 101 | const { attrInfo, deviceId } = unref(dataSourceJson) |
| 98 | const { identifier, extensionDesc, detail, name } = attrInfo || {}// 属性信息 | 102 | const { identifier, extensionDesc, detail, name } = attrInfo || {}// 属性信息 |
| @@ -110,6 +114,7 @@ const open = async (_data: SingleClickEventDataType) => { | @@ -110,6 +114,7 @@ const open = async (_data: SingleClickEventDataType) => { | ||
| 110 | formField.value = identifier | 114 | formField.value = identifier |
| 111 | isShowActionType.value = !!actionType // 判断modBUS类型时 物模型是否填写扩展描述 | 115 | isShowActionType.value = !!actionType // 判断modBUS类型时 物模型是否填写扩展描述 |
| 112 | serviceInfo.callType = callType // 服务命令调用方式 是同步还是异步 | 116 | serviceInfo.callType = callType // 服务命令调用方式 是同步还是异步 |
| 117 | + serviceInfo.way = way || 'oneway' // 命令下发是双向还是单向 | ||
| 113 | 118 | ||
| 114 | serviceInfo.transportType = transportType | 119 | serviceInfo.transportType = transportType |
| 115 | serviceInfo.code = code | 120 | serviceInfo.code = code |
| @@ -268,7 +273,7 @@ const handleSubmit = async () => { | @@ -268,7 +273,7 @@ const handleSubmit = async () => { | ||
| 268 | persistent: true, | 273 | persistent: true, |
| 269 | method: 'methodThingskit', | 274 | method: 'methodThingskit', |
| 270 | params: serviceInfo.transportType !== TransportTypeEnum.TCP && unref(isCommandWay) === CommandDeliveryWayEnum.SERVICE ? { service: unref(sendValue) } : unref(sendValue), | 275 | params: serviceInfo.transportType !== TransportTypeEnum.TCP && unref(isCommandWay) === CommandDeliveryWayEnum.SERVICE ? { service: unref(sendValue) } : unref(sendValue), |
| 271 | - }, dataSourceJson.value.deviceId) | 276 | + }, dataSourceJson.value.deviceId, serviceInfo.way) |
| 272 | createMessage.success('命令下发成功') | 277 | createMessage.success('命令下发成功') |
| 273 | visible.value = false | 278 | visible.value = false |
| 274 | isInputData.value = false | 279 | isInputData.value = false |
| @@ -28,7 +28,6 @@ const [registerForm, formActionType] = useForm({ | @@ -28,7 +28,6 @@ const [registerForm, formActionType] = useForm({ | ||
| 28 | schemas: formSchemas, | 28 | schemas: formSchemas, |
| 29 | showActionButtonGroup: false, | 29 | showActionButtonGroup: false, |
| 30 | layout: FormLayoutEnum.VERTICAL, | 30 | layout: FormLayoutEnum.VERTICAL, |
| 31 | - labelWidth: 70, | ||
| 32 | getPopupContainer: () => document.body, | 31 | getPopupContainer: () => document.body, |
| 33 | fieldMapToTime: [[AlarmListFieldsEnum.ALARM_LIST_QUERY_DATE, [AlarmListFieldsEnum.START_TIME, AlarmListFieldsEnum.END_TIME], DateFormatEnum.X]], | 32 | fieldMapToTime: [[AlarmListFieldsEnum.ALARM_LIST_QUERY_DATE, [AlarmListFieldsEnum.START_TIME, AlarmListFieldsEnum.END_TIME], DateFormatEnum.X]], |
| 34 | }) | 33 | }) |
| @@ -82,7 +81,7 @@ onMounted(async () => { | @@ -82,7 +81,7 @@ onMounted(async () => { | ||
| 82 | </script> | 81 | </script> |
| 83 | 82 | ||
| 84 | <template> | 83 | <template> |
| 85 | - <div class="m-1 w-full"> | 84 | + <div class="m-1 w-full alarm-list-config-from"> |
| 86 | <Divider orientation="left" class="!text-sm"> | 85 | <Divider orientation="left" class="!text-sm"> |
| 87 | 数据绑定 | 86 | 数据绑定 |
| 88 | </Divider> | 87 | </Divider> |
| @@ -95,6 +94,14 @@ onMounted(async () => { | @@ -95,6 +94,14 @@ onMounted(async () => { | ||
| 95 | </div> | 94 | </div> |
| 96 | </template> | 95 | </template> |
| 97 | 96 | ||
| 98 | -<style> | ||
| 99 | - | 97 | +<style lang="less" scoped> |
| 98 | +// .alarm-list-config-form { | ||
| 99 | +// :deep(.ant-picker-input.ant-picker-input-active) { | ||
| 100 | +// >input { | ||
| 101 | +// overflow: hidden; | ||
| 102 | +// text-overflow: ellipsis; | ||
| 103 | +// white-space: nowrap; | ||
| 104 | +// } | ||
| 105 | +// } | ||
| 106 | +// } | ||
| 100 | </style> | 107 | </style> |
| @@ -133,6 +133,14 @@ export const formSchemas: FormSchema[] = [ | @@ -133,6 +133,14 @@ export const formSchemas: FormSchema[] = [ | ||
| 133 | label: AlarmListFieldsNameEnum.ALARM_LIST_INTERVAL, | 133 | label: AlarmListFieldsNameEnum.ALARM_LIST_INTERVAL, |
| 134 | component: ComponentEnum.INPUT_NUMBER, | 134 | component: ComponentEnum.INPUT_NUMBER, |
| 135 | required: false, | 135 | required: false, |
| 136 | + componentProps: { | ||
| 137 | + min: 0, | ||
| 138 | + }, | ||
| 139 | + renderComponentContent: () => { | ||
| 140 | + return { | ||
| 141 | + addonAfter: () => '秒', | ||
| 142 | + } | ||
| 143 | + }, | ||
| 136 | }, | 144 | }, |
| 137 | { | 145 | { |
| 138 | field: AlarmListFieldsEnum.ALARM_LIST_POLLING, | 146 | field: AlarmListFieldsEnum.ALARM_LIST_POLLING, |
| @@ -140,5 +148,13 @@ export const formSchemas: FormSchema[] = [ | @@ -140,5 +148,13 @@ export const formSchemas: FormSchema[] = [ | ||
| 140 | component: ComponentEnum.INPUT_NUMBER, | 148 | component: ComponentEnum.INPUT_NUMBER, |
| 141 | defaultValue: 30, | 149 | defaultValue: 30, |
| 142 | required: false, | 150 | required: false, |
| 151 | + componentProps: { | ||
| 152 | + min: 1, | ||
| 153 | + }, | ||
| 154 | + renderComponentContent: () => { | ||
| 155 | + return { | ||
| 156 | + addonAfter: () => '秒', | ||
| 157 | + } | ||
| 158 | + }, | ||
| 143 | }, | 159 | }, |
| 144 | ] | 160 | ] |
| 1 | <script setup lang="ts"> | 1 | <script setup lang="ts"> |
| 2 | import { computed, nextTick, onMounted, reactive, unref } from 'vue' | 2 | import { computed, nextTick, onMounted, reactive, unref } from 'vue' |
| 3 | -import { Divider, Tag } from 'ant-design-vue' | 3 | +import { Tag } from 'ant-design-vue' |
| 4 | +import { useIntervalFn } from '@vueuse/core' | ||
| 4 | import { ScrollList } from './ScrollList' | 5 | import { ScrollList } from './ScrollList' |
| 5 | import { fetchAlarmList } from '@/api/alarm' | 6 | import { fetchAlarmList } from '@/api/alarm' |
| 6 | import type { AlarmListItemType } from '@/api/alarm/model' | 7 | import type { AlarmListItemType } from '@/api/alarm/model' |
| @@ -14,10 +15,6 @@ const props = defineProps<{ | @@ -14,10 +15,6 @@ const props = defineProps<{ | ||
| 14 | config: CreateComponentType | 15 | config: CreateComponentType |
| 15 | }>() | 16 | }>() |
| 16 | 17 | ||
| 17 | -const getCellBounds = computed( | ||
| 18 | - () => props.config.cellBounds || { width: 290, height: 230, x: 0, y: 0 }, | ||
| 19 | -) | ||
| 20 | - | ||
| 21 | const contentDataStore = useContentDataStore() | 18 | const contentDataStore = useContentDataStore() |
| 22 | 19 | ||
| 23 | const initOptions = reactive<{ | 20 | const initOptions = reactive<{ |
| @@ -67,7 +64,7 @@ onMounted(async () => { | @@ -67,7 +64,7 @@ onMounted(async () => { | ||
| 67 | // 预览模式 | 64 | // 预览模式 |
| 68 | await initFetchAlarmList() | 65 | await initFetchAlarmList() |
| 69 | if (initOptions.polling) | 66 | if (initOptions.polling) |
| 70 | - setInterval(initFetchAlarmList, initOptions.polling * 1000) | 67 | + useIntervalFn(initFetchAlarmList, (initOptions.polling || 30) * 1000) |
| 71 | } | 68 | } |
| 72 | else { | 69 | else { |
| 73 | const statusList = Object.values(AlarmStatusEnum) | 70 | const statusList = Object.values(AlarmStatusEnum) |
| @@ -90,16 +87,13 @@ onMounted(async () => { | @@ -90,16 +87,13 @@ onMounted(async () => { | ||
| 90 | <div class="seamless-scroll w-full h-full flex justify-center items-center overflow-y-scroll"> | 87 | <div class="seamless-scroll w-full h-full flex justify-center items-center overflow-y-scroll"> |
| 91 | <ScrollList | 88 | <ScrollList |
| 92 | v-model="initOptions.scroll" :single-wait-time="initOptions.interval" :list="initOptions.alarmList" | 89 | v-model="initOptions.scroll" :single-wait-time="initOptions.interval" :list="initOptions.alarmList" |
| 93 | - :limit-scroll-num="10" :is-rem-unit="true" :delay="10" :wheel="true" hover :style="{ | ||
| 94 | - width: `${getCellBounds.width}px`, | ||
| 95 | - height: `${getCellBounds.height}px`, | ||
| 96 | - }" | 90 | + :is-rem-unit="true" :delay="10" :wheel="true" hover |
| 97 | > | 91 | > |
| 98 | - <div v-for="(item, index) in initOptions.alarmList" :key="index" class="flex flex-col items-start h-15 px-2"> | ||
| 99 | - <p class="text-xs"> | 92 | + <div v-for="(item, index) in initOptions.alarmList" :key="index" class="flex flex-col items-start p-2 border-gray-600 border-b border-solid border-t-transparent border-l-transparent border-r-transparent"> |
| 93 | + <div class="text-xs mb-2"> | ||
| 100 | <span>设备:</span> | 94 | <span>设备:</span> |
| 101 | <span class="ml-1">{{ item.deviceAlias || item.deviceName }}</span> | 95 | <span class="ml-1">{{ item.deviceAlias || item.deviceName }}</span> |
| 102 | - </p> | 96 | + </div> |
| 103 | <div class="flex items-center justify-between -mt-2 text-xs"> | 97 | <div class="flex items-center justify-between -mt-2 text-xs"> |
| 104 | <span>时间:</span> | 98 | <span>时间:</span> |
| 105 | <span class="ml-1">{{ item.startTs }}</span> | 99 | <span class="ml-1">{{ item.startTs }}</span> |
| @@ -107,19 +101,17 @@ onMounted(async () => { | @@ -107,19 +101,17 @@ onMounted(async () => { | ||
| 107 | {{ AlarmStatusNameEnum[item.status] }} | 101 | {{ AlarmStatusNameEnum[item.status] }} |
| 108 | </Tag> | 102 | </Tag> |
| 109 | </div> | 103 | </div> |
| 110 | - <Divider class="mt-2 divider" /> | ||
| 111 | </div> | 104 | </div> |
| 112 | </ScrollList> | 105 | </ScrollList> |
| 113 | </div> | 106 | </div> |
| 114 | </template> | 107 | </template> |
| 115 | 108 | ||
| 116 | <style scoped lang="less"> | 109 | <style scoped lang="less"> |
| 117 | -.seamless-scroll::-webkit-scrollbar { | ||
| 118 | - display: none; | 110 | +.seamless-scroll { |
| 111 | + | ||
| 112 | + ::-webkit-scrollbar { | ||
| 113 | + display: none; | ||
| 119 | 114 | ||
| 120 | - .divider { | ||
| 121 | - height: 0.3px; | ||
| 122 | - background-color: black; | ||
| 123 | } | 115 | } |
| 124 | } | 116 | } |
| 125 | </style> | 117 | </style> |