Commit 9d8242fb authored by 郭铭瑶's avatar 郭铭瑶 🤘

拆分编辑屏和展示屏

parent b379e1a9
......@@ -16,6 +16,7 @@
"normalize.css": "^8.0.1",
"qs": "^6.10.1",
"vue": "^3.2.6",
"vue3-json-viewer": "^1.0.4",
"vuex": "^4.0.0"
},
"devDependencies": {
......@@ -1527,6 +1528,17 @@
"is-regex": "^1.0.3"
}
},
"node_modules/clipboard": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
"integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
"peer": true,
"dependencies": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
......@@ -1710,6 +1722,12 @@
"node": ">= 0.4"
}
},
"node_modules/delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"peer": true
},
"node_modules/diff-sequences": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
......@@ -2947,6 +2965,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"peer": true,
"dependencies": {
"delegate": "^3.1.2"
}
},
"node_modules/graceful-fs": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
......@@ -4473,6 +4500,12 @@
"@types/jest": "^26.0.20"
}
},
"node_modules/select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"peer": true
},
"node_modules/semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
......@@ -4851,6 +4884,12 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
"node_modules/tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"peer": true
},
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
......@@ -5355,6 +5394,15 @@
"typescript": "*"
}
},
"node_modules/vue3-json-viewer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/vue3-json-viewer/-/vue3-json-viewer-1.0.4.tgz",
"integrity": "sha512-E+FKQ8cGVXeZmS25AMeLlgNkTnewSy6Ex11udMn12ex06XcW3ZTgGfdTvg/oklh49B2pDZN1Osr94QOvgV8h5w==",
"peerDependencies": {
"clipboard": "^2.0.6",
"vue": "^3.0.0-rc.5"
}
},
"node_modules/vueuc": {
"version": "0.4.13",
"resolved": "https://registry.npmjs.org/vueuc/-/vueuc-0.4.13.tgz",
......@@ -6622,6 +6670,17 @@
"is-regex": "^1.0.3"
}
},
"clipboard": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
"integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
"peer": true,
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
......@@ -6780,6 +6839,12 @@
"object-keys": "^1.0.12"
}
},
"delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"peer": true
},
"diff-sequences": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
......@@ -7671,6 +7736,15 @@
"slash": "^3.0.0"
}
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"peer": true,
"requires": {
"delegate": "^3.1.2"
}
},
"graceful-fs": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
......@@ -8825,6 +8899,12 @@
"@types/jest": "^26.0.20"
}
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"peer": true
},
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
......@@ -9127,6 +9207,12 @@
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"peer": true
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
......@@ -9538,6 +9624,12 @@
"vscode-vue-languageservice": "^0.27.0"
}
},
"vue3-json-viewer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/vue3-json-viewer/-/vue3-json-viewer-1.0.4.tgz",
"integrity": "sha512-E+FKQ8cGVXeZmS25AMeLlgNkTnewSy6Ex11udMn12ex06XcW3ZTgGfdTvg/oklh49B2pDZN1Osr94QOvgV8h5w==",
"requires": {}
},
"vueuc": {
"version": "0.4.13",
"resolved": "https://registry.npmjs.org/vueuc/-/vueuc-0.4.13.tgz",
......
......@@ -7,6 +7,7 @@
"dev": "vite",
"start": "npm run dev",
"build": "vue-tsc --noEmit && vite build",
"build:dev": "vite build",
"serve": "vite preview"
},
"dependencies": {
......@@ -19,6 +20,7 @@
"normalize.css": "^8.0.1",
"qs": "^6.10.1",
"vue": "^3.2.6",
"vue3-json-viewer": "^1.0.4",
"vuex": "^4.0.0"
},
"devDependencies": {
......
<template>
<Main />
<n-config-provider
:locale="zhCN"
:date-locale="dateZhCN"
:theme="darkTheme"
:theme-overrides="themeOverrides"
style="width: 100%; height: 100%"
>
<component :is="MainPage" />
</n-config-provider>
<m-loader v-if="showLoading" />
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue'
import Main from './view/main.vue'
<script lang="ts" setup>
import { computed, onMounted, nextTick, ref } from 'vue'
import EditPage from './view/edit-page.vue'
import ViewPage from './view/view-page.vue'
import store from '@/store'
import {
darkTheme,
NConfigProvider,
GlobalThemeOverrides,
zhCN,
dateZhCN,
} from 'naive-ui'
export default defineComponent({
name: 'App',
components: { Main },
setup() {
const showLoading = computed(() => store.state.showLoading)
return {
showLoading,
}
const showLoading = computed(() => store.state.showLoading)
const themeOverrides: GlobalThemeOverrides = {
common: {
fontSizeTiny: '.08rem',
fontSizeSmall: '.09rem',
fontSize: '.1rem',
},
})
}
// 根据token判断是否编辑模式
const { searchParams } = new URL(window.location.href)
const token = searchParams.get('token')
const MainPage = token ? EditPage : ViewPage
// // TODO 滚动
// const isWideScreen = ref(false)
// onMounted(async () => {
// await nextTick()
// const ratio = document.body.offsetWidth / document.body.offsetHeight
// isWideScreen.value = ratio > 3
// })
</script>
<style lang="stylus">
......
......@@ -3,6 +3,7 @@
<img :src="bgImg" class="bg" />
<div class="date">{{ date }} {{ time }}</div>
<img
v-if="editable"
src="@/assets/images/filter.png"
class="filter"
draggable="false"
......@@ -26,6 +27,10 @@ export default defineComponent({
type: String as PropType<string>,
default: bgImg,
},
editable: {
type: Boolean as PropType<boolean>,
default: false,
},
},
emits: ['touch'],
setup(_, ctx) {
......
import { ref } from 'vue'
import componentList, { tabs } from '@/utils/component-list'
import useConfig, { Config } from './useConfig'
import take2rows from '@/utils/take2rows'
export default function useComponent() {
const showComponentModal = ref(false) // 展示组件选择框
const curBox = ref<number | null>(null) // 当前容器下标
const components = ref<Config['components']>({}) // {容器下标: 组件key}
const components = ref<{ [key: number]: string }>({}) // {容器下标: 组件key}
const isTake2rows = ref<boolean>(false)
const config = useConfig() // 获取组件选择配置
if (config?.components) {
components.value = config.components
}
const openComponentModal = (i: number, template: string[]) => {
// 点击容器中的新增按钮
curBox.value = i
......
export interface Config {
layout: { template: string[]; rows: string; boxNum: number }
components: { [key: number]: string }
}
export default function useConfig(config?: string) {
if (config) {
// 保存配置
window.sessionStorage.setItem('__layout_components__', config)
return
}
// 获取配置
const data = window.sessionStorage.getItem('__layout_components__')
if (data) {
return JSON.parse(data) as Config
} else {
return {
layout: {
template: [],
rows: '',
boxNum: 0,
},
components: {},
}
}
}
import { ref } from 'vue'
import useConfig, { Config } from './useConfig'
export default function useLayout() {
const showLayoutModal = ref(false) // 展示布局选择弹窗
const layout = ref<Config['layout']>({
const layout = ref<{ template: string[]; rows: string; boxNum: number }>({
// 布局内容设置
template: [],
rows: '',
boxNum: 0,
})
const config = useConfig() // 获取布局配置
if (config?.layout) {
layout.value = config.layout
}
const onChangeLayout = (key: string) => {
// 选择某一布局后获取布局内容
layout.value = getLayout(key)
......
import { createApp } from 'vue'
import App from './App.vue'
import MyComponent from '@/components/MyComponent'
import { create, NIcon } from 'naive-ui'
import { create, NIcon, NSpace } from 'naive-ui'
import JsonViewer from 'vue3-json-viewer'
const naive = create({
components: [NIcon],
components: [NIcon, NSpace],
})
createApp(App).use(MyComponent).use(naive).mount('#app')
const app = createApp(App)
app.use(MyComponent).use(naive).use(JsonViewer).mount('#app')
......@@ -3,7 +3,7 @@
v-model="visible"
title="布局设定"
width="98vw"
height="93vh"
height="93%"
offset-y=".2rem"
bg-color="rgba(0,0,0,0.5)"
:mask-closable="false"
......@@ -93,7 +93,7 @@ const onClose = () => {
justify-content space-between
.row
.title
width 23%
width 20%
text-align center
p
display inline-block
......@@ -104,7 +104,7 @@ const onClose = () => {
font-weight bold
.img
display inline-block
width 23%
width 20%
margin-right 2%
cursor pointer
border-radius .04rem
......
<template>
<div class="main">
<m-title
area="title"
@click.prevent.stop="save"
@touch="showLayoutModal = true"
>
<m-title area="title" editable @touch="showLayoutModal = true">
静安智慧房管
</m-title>
<m-grid
......@@ -32,12 +28,20 @@
/>
<n-icon
v-show="!!components[index]"
class="del-btn"
class="btn del"
size=".16rem"
@click="onCancelComponent(index)"
>
<TrashBin />
</n-icon>
<n-icon
v-show="!!components[index]"
class="btn config"
size=".16rem"
@click="onSetComponent(componentList[components[index]])"
>
<Settings />
</n-icon>
</div>
</m-grid>
</div>
......@@ -47,6 +51,53 @@
:rows="isTake2rows ? 2 : 1"
@select="onSelectComponent"
/>
<n-drawer id="setting-drawer" v-model:show="showSettingDrawer" :width="502">
<n-drawer-content title="组件设置">
<n-form
ref="formRef"
:model="model"
label-placement="left"
:label-width="80"
size="small"
>
<n-form-item label="标题" path="title">
<n-input v-model:value="model.title" />
</n-form-item>
<n-form-item label="请求地址" path="baseUrl">
<n-input v-model:value="model.baseUrl" />
</n-form-item>
</n-form>
<n-collapse accordion>
<n-collapse-item
v-for="(item, i) in apiList"
:key="item.key"
:title="`接口${i + 1}`"
:name="item.key"
>
<div>
<n-space align="center" justify="space-between">
<n-input v-model:value="item.value" size="small" />
<n-button size="small" @click="testFetchData(item.value, i)">
请求
</n-button>
</n-space>
<json-viewer
v-if="resList[i]"
:value="resList[i]"
:expand-depth="2"
sort
:copyable="{ copyText: '复制', copiedText: '已复制' }"
/>
</div>
</n-collapse-item>
</n-collapse>
<n-space justify="end">
<n-button type="primary" size="small" @click="saveConfig">
保存
</n-button>
</n-space>
</n-drawer-content>
</n-drawer>
</template>
<script lang="ts" setup>
......@@ -55,8 +106,21 @@ import ComponentModal from './components/component-modal.vue'
import useLayout from '@/hooks/useLayout'
import useComponent from '@/hooks/useComponent'
import useConfig from '@/hooks/useConfig'
import { TrashBin } from '@vicons/ionicons5'
import { TrashBin, Settings } from '@vicons/ionicons5'
import { bus } from '@/utils/component-list'
import axios from 'axios'
import {
NDrawer,
NDrawerContent,
NForm,
NFormItem,
NInput,
NButton,
NCollapse,
NCollapseItem,
} from 'naive-ui'
import { onBeforeUnmount, ref } from 'vue'
import { ajax, api } from '@/ajax'
const { showLayoutModal, layout, onChangeLayout } = useLayout()
const {
......@@ -68,21 +132,100 @@ const {
onSelectComponent,
isTake2rows,
} = useComponent()
const save = () => {
const data = {
layout: layout.value,
components: components.value,
const handleMessage = (e) => {
const { type, data } = e.data
console.log('大屏:', e)
switch (type) {
case 'save':
window.parent.postMessage(
{
type: 'config',
data: JSON.stringify({
layout: layout.value,
components: components.value,
}),
},
'*',
)
break
case 'init':
ajax
.get({
url: api.CONFIGS,
params: {
id: data,
},
showLoading: true,
})
.then((res) => {
const { configJson } = res?.data?.content?.[0] || {}
if (!configJson) return
const config = JSON.parse(configJson)
config?.layout && (layout.value = config.layout)
config?.components && (components.value = config.components)
})
break
default:
break
}
useConfig(JSON.stringify(data))
bus.emit('update:A002', [
{ name: '分户', value: 100 },
{ name: '门牌', value: 100 },
{ name: '小区', value: 100 },
])
}
window.addEventListener('message', handleMessage)
onBeforeUnmount(() => {
window.removeEventListener('message', handleMessage)
})
// const save = () => {
// const data = {
// layout: layout.value,
// components: components.value,
// }
// useConfig(JSON.stringify(data))
// bus.emit('update:A002', [
// { name: '分户', value: 100 },
// { name: '门牌', value: 100 },
// { name: '小区', value: 100 },
// ])
// }
bus.on('map', (e: any) => {
console.log('emit by : ', e)
})
const showSettingDrawer = ref(false)
const model = ref<any>({})
const mock = [
{ icon: TrashBin, name: '小区', value: 904 },
{ icon: TrashBin, name: '业委会', value: 400 },
{ icon: TrashBin, name: '物业服务企业', value: 130 },
]
const curComponentName = ref('')
const apiList = ref<{ key: string; value: string }[]>([])
function onSetComponent({ name, title, baseUrl, apis }) {
showSettingDrawer.value = true
model.value = {
title,
baseUrl,
}
curComponentName.value = name
// apiList.value = apis
apiList.value = [
{ key: 'summary', value: '/api1' },
{ key: 'list', value: '/api2' },
]
}
const resList = ref<any[]>([])
async function testFetchData(api, i) {
resList.value[i] =
(
await axios.get(
'http://yapi.omniview.pro/mock/377/service-special-nandong/forOld/statistics',
)
)?.data?.data?.content || null
}
function saveConfig() {
const config = { ...model.value }
bus.emit(`config-${curComponentName.value}`, config)
}
</script>
<style lang="stylus" scoped>
......@@ -100,7 +243,7 @@ bus.on('map', (e: any) => {
position relative
overflow hidden
&:hover
>.del-btn
>.btn
opacity 0.7
&.done
border none
......@@ -120,14 +263,30 @@ bus.on('map', (e: any) => {
opacity 1
width .24rem
height @width
>.del-btn
>.btn
position absolute
top .05rem
right .05rem
cursor pointer
color red
opacity 0
transition opacity .2s ease-in-out
&.del
right .05rem
color red
&.config
right .25rem
color $blue
&:hover
opacity 1
</style>
<style lang="stylus">
@import '../components/MyComponent/main.styl'
#setting-drawer
font-size .1rem
background $primary-bg
$blur()
.jv-container
margin .1rem 0
.jv-code
padding .05rem .1rem
</style>
<template>
<div class="main">
<m-title area="title"> 静安智慧房管 </m-title>
<m-grid
v-if="layout.boxNum > 0"
:template="layout.template"
columns="1fr 1.5fr 1fr"
:rows="`${layout.rows}`"
>
<div
v-for="(_, index) in new Array(layout.boxNum)"
:key="index"
class="box"
:area="`box${index + 1}`"
>
<component
:is="componentList[components[index]]"
v-if="!!components[index]"
/>
</div>
</m-grid>
</div>
</template>
<script lang="ts" setup>
import useLayout from '@/hooks/useLayout'
import useComponent from '@/hooks/useComponent'
const { layout } = useLayout()
const { components, componentList } = useComponent()
</script>
<style lang="stylus" scoped>
@import '../components/MyComponent/main.styl'
.main
width 100%
height 100%
display flex
flex-direction column
.box
border-radius .02rem
background transparent
$blur(0)
position relative
overflow hidden
</style>
......@@ -12,6 +12,6 @@ export default defineConfig({
},
},
server: {
port: 3001,
port: 3000,
},
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment