lvkun 2 лет назад
Родитель
Сommit
6371e888eb

+ 43 - 5
src/components/MicroComponents/index.tsx

@@ -1,7 +1,7 @@
-import { defineComponent, ref } from 'vue'
-import { LoadingOutlined, ReloadOutlined, CopyTwoTone } from '@ant-design/icons-vue'
+import { PropType, defineComponent, ref } from 'vue'
+import { LoadingOutlined, ReloadOutlined, CopyTwoTone, EditOutlined } from '@ant-design/icons-vue'
 import { useCopy } from '@/hooks/dom'
-import { Input } from 'ant-design-vue'
+import { Input, Space, Button } from 'ant-design-vue'
 
 /* 此代码导出一个名为“ReloadIconTsx”的 Vue
 组件,该组件显示一个用于重新加载内容的图标。该组件有两个道具:`loading`(一个布尔值,指示内容当前是否正在加载)和`reload`(单击重新加载图标时调用的函数)。该组件使用 Vue
@@ -138,14 +138,52 @@ export const InputTsx = defineComponent({
     placeholder: {
       type: String,
       default: '输入点什么...'
+    },
+    mode: {
+      type: String as PropType<'normal' | 'edit'>,
+      default: 'normal'
     }
   },
-  emits: ['update:value'],
+  emits: ['update:value', 'submit'],
   setup (props, ctx) {
+    const editing = ref<boolean>(false)
+
     const onInput = (value: string) => ctx.emit('update:value', value)
 
+    const submitUpdate = () => {
+      ctx.emit('submit')
+      editing.value = false
+    }
+
     return () => (
-      <Input style={{ minWidth: '170px' }} placeholder={props.placeholder} value={props.modelValue} onChange={(e) => onInput(e.target.value!)} />
+      <>
+        {
+          props.mode === 'normal'
+            ? <Input style={{ minWidth: '170px' }} placeholder={props.placeholder} value={props.modelValue} onChange={(e) => onInput(e.target.value!)} />
+            : <>
+              <Space>
+                {
+                  editing.value ? <Input style={{ minWidth: '170px' }} placeholder={props.placeholder} value={props.modelValue} onChange={(e) => onInput(e.target.value!)} /> : <div style={{ minWidth: '170px' }} >{props.modelValue}</div>
+                }
+                {
+                  editing.value ? <EditOutlined style={{ cursor: 'pointer' }} onClick={() => editing.value = !editing.value} /> : null
+                }
+
+              </Space>
+              {
+                editing.value
+                  ? <Space>
+                <Button type="primary" onClick={() => submitUpdate()}>确定</Button>
+                <Button onClick={() => editing.value = false}>取消</Button>
+              </Space>
+                  : null
+              }
+
+          </>
+        }
+
+      </>
+
     )
   }
 })

+ 35 - 0
src/components/RealView/index.less

@@ -0,0 +1,35 @@
+
+.real-view {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 99;
+  background-color: #f7f7f9;
+  .header {
+    height: 48px;
+    display: flex;
+    align-items: center;
+    padding-left: 18px;
+    background-color: #fff;
+    .back-button {
+      display: flex;
+      align-items: center;
+      cursor: pointer;
+    }
+  }
+  .tabs {
+    width: 100%;
+    height: 45px;
+    background-color: #fff;
+    padding-left: 10px;
+  }
+  .real-view-content {
+    width: 100%;
+    padding: 18px;
+    box-sizing: border-box;
+    overflow: hidden;
+    overflow-y: scroll;
+  }
+}

+ 71 - 0
src/components/RealView/index.tsx

@@ -0,0 +1,71 @@
+import { defineComponent, onMounted, PropType, ref, Teleport, toRef, toRefs } from 'vue'
+import { Row, Col, Tabs } from 'ant-design-vue'
+import { LeftOutlined } from '@ant-design/icons-vue'
+import './index.less'
+
+const RealView = defineComponent({
+
+  props: {
+    open: {
+      type: Boolean,
+      default: false
+    },
+    tabKey: {
+      type: String,
+      default: ''
+    },
+    tabsList: {
+      type: Array as PropType<{key: string, tab: string}[]>,
+      default: () => []
+    }
+  },
+  emits: ['cancel', 'tabChang'],
+  setup (props, ctx) {
+    const { open, tabKey, tabsList } = toRefs(props)
+
+    const cancel = () => {
+      console.log('cancel:')
+      ctx.emit('cancel')
+    }
+
+    const onTabChange = (key) => ctx.emit('tabChang', key)
+
+    const TabsRender =
+      <div class="tabs" key={tabKey.value}>
+        <Tabs activeKey={tabKey.value} tabBarStyle={{ backgroundColor: 'fff', height: '45px' }} onChange={(key) => onTabChange(key)} >
+          { tabsList.value.map(item => <Tabs.TabPane key={item.key} tab={item.tab}> </Tabs.TabPane>) }
+        </Tabs>
+      </div>
+
+    return () => (
+      <>
+      {
+        open.value
+          ? <Teleport to='#content' >
+              <div class='real-view' id='real-view'>
+              <Row class='header' >
+                <div class="back-button" onClick={() => cancel()} >
+                  <LeftOutlined style={{ fontSize: '18px', color: '#ccc' }} />
+                  <span style={{ fontSize: '18px' }} >返回</span>
+                </div>
+              </Row>
+              <div class="tabs" >
+        <Tabs activeKey={tabKey.value} tabBarStyle={{ backgroundColor: 'fff', height: '45px' }} onChange={(key) => onTabChange(key)} >
+          { tabsList.value.map(item => <Tabs.TabPane key={item.key} tab={item.tab}> </Tabs.TabPane>) }
+        </Tabs>
+      </div>
+              <div class='real-view-content' >
+              {ctx.slots.default?.()}
+              </div>
+
+            </div>
+          </Teleport>
+
+          : null
+      }
+      </>
+    )
+  }
+})
+
+export { RealView }

+ 7 - 1
src/layout/layout.vue

@@ -3,7 +3,7 @@
       <Navbar />
       <a-layout >
         <SiderBar />
-        <div class="content"  >
+        <div class="content" id="content"  >
           <RouterTravel />
           <div class="router-view" >
             <RouterView :key="useRouterTravel.keyCount" ></RouterView>
@@ -18,9 +18,14 @@ import Navbar from './navbar.vue'
 import SiderBar from './components/Sidebar/index.vue'
 import RouterTravel from './routerTravel.vue'
 import { useRouterTravelStore } from '@/store'
+import { onMounted } from 'vue'
 
 const useRouterTravel = useRouterTravelStore()
 
+onMounted(() => {
+
+})
+
 </script>
 
 <style lang="less" scoped >
@@ -35,6 +40,7 @@ const useRouterTravel = useRouterTravelStore()
     border-top-left-radius: 24px;
     // overflow: hidden;
     // overflow-y: scroll;
+    position: relative;
     .router-view {
       width: 100%;
       height: 100%;

+ 2 - 2
src/pages/cvs/project/index.vue

@@ -48,8 +48,8 @@ const columns = [
   },
   {
     title: '操作',
-    dataIndex: 'key',
-    key: 'key'
+    dataIndex: 'action',
+    key: 'action'
   }
 ]
 

+ 78 - 15
src/pages/cvs/video/device.vue

@@ -35,6 +35,7 @@
 
       <template v-if="column.key === 'action'" >
         <a-space>
+          <a @click="baseInfo(record)">基本信息</a>
           <a @click="recordParty(record)">录像回放</a>
           <a @click="thumbParty(record)">截图查看</a>
           <a @click="arAnalysis(record)">AI分析</a>
@@ -67,20 +68,34 @@
       <a-form-item  label="设备地址"  >
         <InputTsx allowClear placeholder="请输入设备地址" v-model:value="deviceState.gisName" />
       </a-form-item>
-      <!-- <a-form-item  label="设备经纬度"  >
-        <InputTsx allowClear placeholder="输入地址后自动填入经纬度,例如(116.404,39.915)" />
-      </a-form-item> -->
+      <a-form-item  label="拉流地址"  >
+        <InputTsx v-model:value="deviceState.pullPath" placeholder="请输入拉流地址" />
+      </a-form-item>
+      <a-form-item  label="国标Id"  >
+        <InputTsx v-model:value="deviceState.gbConfig.gbId" placeholder="请输入拉流地址" />
+      </a-form-item>
+      <a-form-item  label="用户名"  >
+        <InputTsx v-model:value="deviceState.gbConfig.username" placeholder="请输入用户名"/>
+      </a-form-item>
+      <a-form-item  label="用户密码"  >
+        <InputTsx v-model:value="deviceState.gbConfig.password" placeholder="请输入用户密码" />
+      </a-form-item>
+      <a-form-item  label="国标平台"  >
+        <a-radio-group v-model:value="deviceState.gbConfig.platform" button-style="solid">
+        <a-radio-button value="IPC">IPC</a-radio-button>
+        <a-radio-button value="NVR">NVR</a-radio-button>
+        </a-radio-group>
+      </a-form-item>
       <a-form-item  label="设备描述"  >
         <a-textarea v-model:value="deviceState.description" placeholder="请输入设备描述" :rows="4" />
       </a-form-item>
     </a-form>
   </modal-pro>
 </a-card>
-
+<!--   :open="state.activeVisible" -->
 <modal-pro
   width="1000px"
   :label="deviceState.deviceName"
-  :open="state.activeVisible"
   @cancel="state.activeVisible = false"
   @ok="state.activeVisible = false"
 >
@@ -89,7 +104,27 @@
     :active-tab-key="activeTabKey"
     @tabChange="key => onTabChange(key)"
   >
-      <a-space>
+
+  </a-card>
+</modal-pro>
+
+<RealView
+  :open="state.activeVisible"
+  @cancel="state.activeVisible = false"
+  :tab-key="activeTabKey"
+  :tabs-list="deviceTabs"
+  @tab-chang="key => onTabChange(key)"
+>
+    <!--  个人基础信息 -->
+    <div v-if="activeTabKey === 'base'" >
+      <a-card title="基本信息" >
+          <a-row>
+            <a-col> <InputTsx mode="edit" ></InputTsx>  </a-col>
+          </a-row>
+      </a-card>
+    </div>
+      <a-card style="background-color: #fff;width: 100%;" v-if="activeTabKey !== 'base'" >
+        <a-space >
           <a-range-picker v-model:value="deviceActionParams.times" />
           <a-select style="width: 170px;"  v-if="activeTabKey === 'record'" v-model:value="deviceActionParams.recordFormat" >
             <a-select-option v-for="item in SpaceController.recordFormat" :key="item" :value="item" >
@@ -103,9 +138,11 @@
           </a-select>
           <a-button type="primary" @click="searchDevice">搜索</a-button>
         </a-space>
+      </a-card>
+
         <!-- 视频 图片区域 -->
-        <a-spin :spinning="state.loading">
-          <a-row :gutter="[8, 8]" style="margin-top: 20px;" >
+      <a-spin :spinning="state.loading">
+          <a-row :gutter="[8, 8]" style="margin-top: 20px;background-color: #fff;" >
             <a-col :span="4" v-for="item in state.deviceMediaList" :key="item" >
               <div class="media-card">
                   <video
@@ -129,9 +166,9 @@
               </div>
             </a-col>
           </a-row>
-        </a-spin>
-  </a-card>
-</modal-pro>
+      </a-spin>
+</RealView>
+
 </template>
 <script lang='ts' setup >
 import { InputTsx } from '@/components/MicroComponents/index'
@@ -140,6 +177,7 @@ import { Form } from 'ant-design-vue'
 import { OperatorController, SpaceController } from '@/controller'
 import { useRoute } from 'vue-router'
 import dayjs from 'dayjs'
+import { RealView } from '@/components/RealView/index'
 
 const columns = [
   {
@@ -182,9 +220,10 @@ const deviceName = ref(null)
 
 const tableProDom = ref()
 
-const activeTabKey = ref<'record' | 'thumb' | 'ai'>('record')
+const activeTabKey = ref<'base' | 'record' | 'thumb' | 'ai'>('base')
 
 const deviceTabs = [
+  { key: 'base', tab: '基础信息' },
   { key: 'record', tab: '录像回放' },
   { key: 'thumb', tab: '截图查看' },
   { key: 'ai', tab: 'AI分析' }
@@ -307,7 +346,14 @@ const deviceState = reactive({
   gisLongitude: '',
   gisLatitude: '',
   gisName: '',
-  type: 'RTSP'
+  type: 'RTSP',
+  pullPath: '',
+  gbConfig: {
+    gbId: '',
+    username: '',
+    password: '',
+    platform: 'IPC'
+  }
 })
 
 const { resetFields, validate, validateInfos } = useForm(deviceState, {
@@ -319,6 +365,8 @@ const { resetFields, validate, validateInfos } = useForm(deviceState, {
 const searchDevice = () => getMedia()
 
 const onTabChange = (key: 'record' | 'thumb' | 'ai') => {
+  console.log('key:', key)
+
   activeTabKey.value = key
 }
 
@@ -339,6 +387,11 @@ const ok = () => {
   }).catch(() => {})
 }
 
+const baseInfo = (record: CVS.device) => {
+  state.activeVisible = true
+  activeTabKey.value = 'base'
+}
+
 const recordParty = async (record: CVS.device) => {
   state.activeVisible = true
   resetFields({ ...record })
@@ -347,10 +400,20 @@ const recordParty = async (record: CVS.device) => {
   getMedia()
 }
 
-const thumbParty = (record: CVS.device) => {}
+const thumbParty = (record: CVS.device) => {
+  state.activeVisible = true
+  resetFields({ ...record })
+  deviceActionParams.deviceId = record.deviceId as unknown as string
+  activeTabKey.value = 'thumb'
+  getMedia()
+}
 
 const arAnalysis = (record: CVS.device) => {
-
+  state.activeVisible = true
+  resetFields({ ...record })
+  deviceActionParams.deviceId = record.deviceId as unknown as string
+  activeTabKey.value = 'ai'
+  getMedia()
 }
 
 const onChangeSpace = (spaceId: string) => {