Procházet zdrojové kódy

init 初始化提交代码

tangning před 8 měsíci
rodič
revize
e1f5f7cc33

+ 4 - 2
package.json

@@ -23,9 +23,11 @@
     "sass": "^1.64.2",
     "unplugin-element-plus": "^0.7.2",
     "unplugin-vue-define-options": "^1.3.12",
+    "vite-plugin-windicss": "^1.9.4",
     "vue": "^3.3.4",
     "vue-cropper": "^1.0.9",
-    "vue-router": "^4.2.4"
+    "vue-router": "^4.2.4",
+    "windicss": "^3.5.6"
   },
   "devDependencies": {
     "@types/node": "^20.4.5",
@@ -34,4 +36,4 @@
     "vite": "^4.4.5",
     "vue-tsc": "^1.8.5"
   }
-}
+}

+ 6 - 0
src/app/criminal/routeConfig.ts

@@ -9,6 +9,12 @@ export const CriminalRouteName = {
 export const menuRouteNames = [
   // CriminalRouteName.statistics,
   CriminalRouteName.vrmodel,
+  CriminalRouteName.abstract,
+  CriminalRouteName.originalPhoto,
+  CriminalRouteName.material,
+  CriminalRouteName.other,
+  CriminalRouteName.aiList,
+  CriminalRouteName.dossier,
   CriminalRouteName.camera,
   CriminalRouteName.example,
   CriminalRouteName.organization,

+ 1 - 1
src/app/criminal/view/login/index.vue

@@ -150,7 +150,7 @@ const submitClick = async () => {
       url.searchParams.append("token", user.value.token);
       window.location.replace(url);
     } else {
-      router.replace({ name: RouteName.scene });
+      router.replace({ name: RouteName.scene, params: { caseId: 360 } });
     }
   } catch (e) {
     console.error(e);

+ 0 - 1
src/app/index.ts

@@ -31,7 +31,6 @@ export type AppConstant = {
 export let appConstant: AppConstant;
 export let appRoutes: Routes;
 export let menuRouteNames: string[];
-
 // 为了打包去除不需要的app只能固定写法
 if (VITE_APP_APP === "fire") {
   appRoutes = fireRoutes;

+ 1 - 1
src/app/xmfire/view/login/index.vue

@@ -155,7 +155,7 @@ const submitClick = async () => {
       url.searchParams.append("token", user.value.token);
       window.location.replace(url);
     } else {
-      router.replace({ name: RouteName.scene });
+      router.replace({ name: RouteName.scene, params: { caseId: 360 } });
     }
   } catch (e) {
     console.error(e);

+ 1 - 1
src/components/head/index.vue

@@ -47,7 +47,7 @@ const props = withDefaults(
   }
 );
 
-const activeValue = ref(props.modelValue || props.options[0].value);
+const activeValue = ref(props.modelValue || props.options[0]?.value);
 const emit = defineEmits<{ (e: "update:modelValue", modelValue: string): void }>();
 const updateModelValue = (modelValue: string) => {
   if ("modelValue" in props) {

+ 64 - 0
src/constant/caseFile.ts

@@ -11,3 +11,67 @@ export const DrawFormatDesc = "jpg、png等格式的文件";
 export const OtherFormatDesc = "pdf、word、jpg、png等格式的文件";
 
 export const maxFileSize = 100 * 1024 * 1024;
+
+export const fileOptions  = [
+  {
+    value: '中心现场照片',
+    label: '中心现场照片',
+    children: [
+      {
+        value: '方位',
+        label: '方位'
+      },{
+        value: '概貌',
+        label: '概貌'
+      },{
+        value: '重点部位',
+        label: '重点部位'
+      },{
+        value: '细目',
+        label: '细目'
+      },{
+        value: '其他',
+        label: '其他'
+      },
+    ]
+  },
+  {
+    value: '关联现场照片',
+    label: '关联现场照片',
+    children: [
+      {
+        value: '尸检照片',
+        label: '尸检照片'
+      },{
+        value: '其他',
+        label: '其他'
+      },
+    ]
+  },
+  {
+    value: '痕迹物证照片',
+    label: '痕迹物证照片',
+    children: [
+      {
+        value: '尸体',
+        label: '尸体'
+      },{
+        value: '手印',
+        label: '手印'
+      },{
+        value: '足迹',
+        label: '足迹'
+      },{
+        value: '血迹',
+        label: '血迹'
+      },{
+        value: '其他',
+        label: '其他'
+      },
+    ]
+  },
+  {
+    value: '其他',
+    label: '其他',
+  },
+]

+ 1 - 0
src/main.ts

@@ -8,6 +8,7 @@ import ElementPlus from "element-plus";
 import { setApp } from "@/helper/mount";
 import { router } from "./router";
 import { appConstant } from "./app";
+import 'virtual:windi.css'
 import "@/store/system";
 
 const app = createApp(App);

+ 38 - 1
src/router/config.ts

@@ -44,11 +44,48 @@ export const routes: Routes = [
       ...system,
       {
         name: RouteName.vrmodel,
-        path: "home",
+        path: "home/:caseId",
         component: () => import("@/view/vrmodel/index.vue"),
+        
         meta: { title: "场景管理", icon: "iconfire_scenes" },
       },
       {
+        name: RouteName.abstract,
+        path: "abstract/:caseId",
+        component: () => import("@/view/abstract/index.vue"),
+        meta: { title: "简要案情", icon: "iconfire_scenes" },
+      },
+      {
+        name: RouteName.originalPhoto,
+        path: "originalPhoto/:caseId",
+        component: () => import("@/view/originalPhoto/index.vue"),
+        meta: { title: "原始照片", icon: "iconfire_scenes" },
+      },
+      {
+        name: RouteName.material,
+        path: "material/:caseId",
+        component: () => import("@/view/material/index.vue"),
+        meta: { title: "三录材料", icon: "iconfire_scenes" },
+      },
+      {
+        name: RouteName.other,
+        path: "other/:caseId",
+        component: () => import("@/view/other/index.vue"),
+        meta: { title: "其他材料", icon: "iconfire_scenes" },
+      },
+      {
+        name: RouteName.aiList,
+        path: "aiList/:caseId",
+        component: () => import("@/view/aiList/index.vue"),
+        meta: { title: "AI 勘察", icon: "iconfire_scenes" },
+      },
+      {
+        name: RouteName.dossier,
+        path: "dossier/:caseId",
+        component: () => import("@/view/dossier/index.vue"),
+        meta: { title: "案件卷宗", icon: "iconfire_scenes" },
+      },
+      {
         name: RouteName.camera,
         path: "camera",
         component: () => import("@/view/camera/index.vue"),

+ 1 - 1
src/router/index.ts

@@ -11,7 +11,7 @@ export const router = createRouter({
 
 router.beforeEach((to, from, next) => {
   if (!to.name || to.name === RouteName.viewLayout) {
-    router.replace({ name: RouteName.scene });
+    router.replace({ name: RouteName.scene, params: { caseId: 360 } });
     return;
   }
   next();

+ 6 - 0
src/router/routeName.ts

@@ -15,6 +15,12 @@ export const RouteName = {
   role: "role",
   sceneInitiator: "sceneInitiator",
   sceneVisitor: "sceneVisitor",
+  abstract: "abstract",
+  originalPhoto: "originalPhoto",
+  material: "material",
+  other: "other",
+  aiList: "aiList",
+  dossier: "dossier",
 } as const;
 
 type RouteNamesType = typeof RouteName;

+ 4 - 3
src/store/permission.ts

@@ -20,10 +20,11 @@ changSaveLocal("permission", () => permission.value);
  */
 export const getPermissionRoutes = (routeNames: string[]) => {
   console.error(permission.value);
+  console.error(pubPermissions,routeNames, 'routeNames');
+  // .filter((routeName) =>
+  //   permission.value.some((p) => p.resourceKey === routeName)
+  // )
   return routeNames
-    .filter((routeName) =>
-      permission.value.some((p) => p.resourceKey === routeName)
-    )
     .map((routeName) => findRoute(routeName))
     .filter((route) => route) as Routes;
 };

+ 307 - 0
src/view/abstract/index.vue

@@ -0,0 +1,307 @@
+<template>
+  <div class="abstract">
+    <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick">
+      <el-tab-pane label="案件信息" name="1" />
+      <el-tab-pane label="勘验信息" name="2" />
+    </el-tabs>
+    <el-form
+      ref="ruleFormRef"
+      :model="ruleForm"
+      label-position="top"
+      :rules="rules"
+      label-width="auto"
+      class="demo-ruleForm"
+      size="default"
+      status-icon
+    >
+      <div class="form-content" v-if="activeName == 1">
+        <el-form-item label="案件名称" required>
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="立案编号" prop="name">
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="案件类别" prop="name">
+          <el-input v-model="ruleForm.name" placeholder="请输入" />
+        </el-form-item>
+        <el-form-item label="案发时间" required>
+          <el-date-picker
+            v-model="ruleForm.date1"
+            type="date"
+            aria-label="Pick a date"
+            placeholder="Pick a date"
+            style="width: 100%"
+          />
+        </el-form-item>
+
+        <el-form-item label="案发区域" prop="name">
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="案发地点" prop="name">
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="是否命案" prop="region">
+          <el-select v-model="ruleForm.region" placeholder="请选择">
+            <el-option label="是" value="1" />
+            <el-option label="否" value="0" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="是否刑案" prop="region">
+          <el-select v-model="ruleForm.region" placeholder="请选择">
+            <el-option label="是" value="1" />
+            <el-option label="否" value="0" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="经纬度" prop="name">
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+      </div>
+      <div class="form-content" v-else>
+        <el-form-item label="指挥中心电话时间" required>
+          <el-date-picker
+            v-model="ruleForm.date1"
+            type="date"
+            aria-label="Pick a date"
+            placeholder="Pick a date"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="接警时间" required>
+          <el-date-picker
+            v-model="ruleForm.date1"
+            type="date"
+            aria-label="Pick a date"
+            placeholder="Pick a date"
+            style="width: 100%"
+          />
+        </el-form-item>
+        <el-form-item label="报警人" required>
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="现场勘验单位" required>
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="指派/报告单位" required>
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="指派方式" required>
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+        <el-form-item label="勘验时间">
+          <el-date-picker
+            v-model="ruleForm.date1"
+            type="daterange"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            format="YYYY-MM-DD"
+            date-format="YYYY/MM/DD ddd"
+          />
+          <!-- <el-col :span="11">
+            <el-date-picker
+              v-model="ruleForm.date1"
+              type="date"
+              placeholder="Pick a date"
+              style="width: 100%"
+            />
+          </el-col>
+          <el-col :span="2" class="text-center">
+            <span class="text-gray-500">-</span>
+          </el-col>
+          <el-col :span="11">
+            <el-time-picker
+              v-model="ruleForm.date2"
+              placeholder="Pick a time"
+              style="width: 100%"
+            />
+          </el-col> -->
+        </el-form-item>
+        <el-form-item label="勘验地点" required>
+          <el-input
+            v-model="ruleForm.name"
+            placeholder="请输入"
+            show-word-limit
+            maxlength="100"
+          />
+        </el-form-item>
+      </div>
+
+      <el-form-item>
+        <el-button
+          class="w-full"
+          type="primary"
+          @click="submitForm(ruleFormRef)"
+        >
+          保存
+        </el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref, reactive } from "vue";
+const active = ref(true);
+const ruleFormRef = ref(null);
+const activeName = ref("1");
+const ruleForm = reactive({
+  name: "Hello",
+  region: "",
+  count: "",
+  date1: "",
+  date2: "",
+  delivery: false,
+  location: "",
+  type: [],
+  resource: "",
+  desc: "",
+});
+const options = Array.from({ length: 10000 }).map((_, idx) => ({
+  value: `${idx + 1}`,
+  label: `${idx + 1}`,
+}));
+const rules = reactive({
+  name: [
+    { required: true, message: "Please input Activity name", trigger: "blur" },
+    { min: 3, max: 5, message: "Length should be 3 to 5", trigger: "blur" },
+  ],
+  region: [
+    {
+      required: true,
+      message: "Please select Activity zone",
+      trigger: "change",
+    },
+  ],
+  count: [
+    {
+      required: true,
+      message: "Please select Activity count",
+      trigger: "change",
+    },
+  ],
+  date1: [
+    {
+      type: "date",
+      required: true,
+      message: "Please pick a date",
+      trigger: "change",
+    },
+  ],
+  date2: [
+    {
+      type: "date",
+      required: true,
+      message: "Please pick a time",
+      trigger: "change",
+    },
+  ],
+  location: [
+    {
+      required: true,
+      message: "Please select a location",
+      trigger: "change",
+    },
+  ],
+  type: [
+    {
+      type: "array",
+      required: true,
+      message: "Please select at least one activity type",
+      trigger: "change",
+    },
+  ],
+  resource: [
+    {
+      required: true,
+      message: "Please select activity resource",
+      trigger: "change",
+    },
+  ],
+  desc: [
+    { required: true, message: "Please input activity form", trigger: "blur" },
+  ],
+});
+const showModal = ref(false);
+const submitForm = async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log("submit!");
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+};
+const resetForm = (formEl) => {
+  if (!formEl) return;
+  formEl.resetFields();
+};
+function handleActive(params) {
+  console.log("handleActive", params);
+}
+async function handleAdd() {
+  console.log("handleAdd");
+}
+</script>
+<style lang="scss" scoped>
+.abstract {
+  height: 100%;
+  .el-form-item--label-top {
+    margin-bottom: 14px;
+  }
+  .form-content {
+    height: calc(100vh - 225px);
+    overflow-y: scroll;
+  }
+  .demo-tabs {
+    .el-tabs__item {
+      height: 32px;
+      line-height: 32px;
+    }
+  }
+}
+</style>

+ 87 - 0
src/view/aiList/index.vue

@@ -0,0 +1,87 @@
+<template>
+  <div class="abstract">
+    <div>场景列表</div>
+    <div>仅 Mesh 场景支持 AI 现勘,请在列表中选择一个场景</div>
+    <div class="blList">
+      <div class="listItem py-2" v-for="item in 3" :key="itme">
+        <div class="title1">场景{{ item }}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref, reactive } from "vue";
+import { addCaseFile } from "../originalPhoto/quisk";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { useUpload } from "@/hook/upload";
+import { Delete, Edit } from "@element-plus/icons-vue";
+const active = ref(true);
+const srcList = [
+  "https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg",
+  "https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg",
+];
+const settype = ref(false);
+const ruleFormRef = ref(null);
+const activeName = ref("1");
+const showModal = ref(false);
+const { size, fileList, upload, removeFile, previewFile, file, accept } =
+  useUpload({
+    maxSize: 10 * 1024 * 1024,
+    formats: [".word", ".pdf"],
+  });
+const handleClick = (tab) => {
+  console.log(tab);
+};
+const submitForm = async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log("submit!");
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+};
+const resetForm = (formEl) => {
+  if (!formEl) return;
+  formEl.resetFields();
+};
+function handleActive(params) {
+  console.log("handleActive", params);
+}
+async function handleAdd() {
+  await addCaseFile({ caseId: 2, fileType: 1 });
+  console.log("handleAdd");
+}
+function handleDel() {
+  ElMessageBox.confirm("确定删除?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    ElMessage({
+      type: "success",
+      message: "删除成功",
+    });
+  });
+}
+</script>
+<style lang="scss" scoped>
+.abstract {
+  height: 100%;
+  .el-form-item--label-top {
+    margin-bottom: 14px;
+  }
+  .form-content {
+    height: calc(100vh - 225px);
+    overflow-y: scroll;
+  }
+  .demo-tabs {
+    .el-tabs__item {
+      height: 32px;
+      line-height: 32px;
+    }
+  }
+}
+</style>

+ 154 - 0
src/view/dossier/index.vue

@@ -0,0 +1,154 @@
+<template>
+  <div class="abstract">
+    <div class="blfrom">
+      <div class="fromTitle">侦查实验</div>
+      <el-upload
+        class="upload-demo"
+        :multiple="false"
+        drag
+        :limit="1"
+        :disabled="!!file"
+        :before-upload="upload"
+        :file-list="fileList"
+        :http-request="() => {}"
+        :on-preview="previewFile"
+        :accept="accept"
+        :before-remove="removeFile"
+      >
+        <div type="primary" :disabled="!!file">
+          <div>点击或拖拽文件上传</div>
+          <div class="">支持 pdf、word 格式图片上传</div>
+        </div>
+      </el-upload>
+    </div>
+    <div class="blfrom">
+      <div class="fromTitle">其他材料</div>
+      <el-upload
+        class="upload-demo"
+        :multiple="false"
+        drag
+        :limit="1"
+        :disabled="!!file"
+        :before-upload="upload"
+        :file-list="fileList"
+        :http-request="() => {}"
+        :on-preview="previewFile"
+        :accept="accept"
+        :before-remove="removeFile"
+      >
+        <div type="primary" :disabled="!!file">
+          <div>点击或拖拽文件上传</div>
+          <div class="">支持 pdf、word 格式图片上传</div>
+        </div>
+      </el-upload>
+    </div>
+    <div class="blList">
+
+      <div class="listItem py-2" v-for="item in 3" :key="itme">
+                <div class="title1">一级标题</div>
+                <div class="list2">
+                  <div class="title2">2级标题</div>
+
+                  <div
+                    class="item2 inline-block relative"
+                    v-for="(item2, index) in srcList"
+                    :key="index"
+                  >
+                    <el-icon
+                      :size="20"
+                      class="absolute z-1 cursor-pointer"
+                      style="right: -0px; top: -8px"
+                    >
+                      <CircleCloseFilled @click="handleDel" />
+                    </el-icon>
+                    <el-image
+                      class="z-0 relative"
+                      :preview-src-list="srcList"
+                      preview-teleported
+                      :initial-index="index"
+                      style="width: 80px; height: 80px; margin-right: 10px"
+                      :src="item2"
+                      :fit="fit"
+                    />
+                  </div>
+                </div>
+              </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref, reactive } from "vue";
+import { addCaseFile } from "../originalPhoto/quisk";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { useUpload } from "@/hook/upload";
+import { Delete, Edit } from "@element-plus/icons-vue";
+const active = ref(true);
+const srcList = [
+  "https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg",
+  "https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg",
+];
+const settype = ref(false);
+const ruleFormRef = ref(null);
+const activeName = ref("1");
+const showModal = ref(false);
+const { size, fileList, upload, removeFile, previewFile, file, accept } =
+  useUpload({
+    maxSize: 10 * 1024 * 1024,
+    formats: [".word", ".pdf"],
+  });
+const handleClick = (tab) => {
+  console.log(tab);
+};
+const submitForm = async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log("submit!");
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+};
+const resetForm = (formEl) => {
+  if (!formEl) return;
+  formEl.resetFields();
+};
+function handleActive(params) {
+  console.log("handleActive", params);
+}
+async function handleAdd() {
+  await addCaseFile({ caseId: 2, fileType: 1 });
+  console.log("handleAdd");
+}
+function handleDel() {
+  ElMessageBox.confirm("确定删除?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    ElMessage({
+      type: "success",
+      message: "删除成功",
+    });
+  });
+}
+</script>
+<style lang="scss" scoped>
+.abstract {
+  height: 100%;
+  .el-form-item--label-top {
+    margin-bottom: 14px;
+  }
+  .form-content {
+    height: calc(100vh - 225px);
+    overflow-y: scroll;
+  }
+  .demo-tabs {
+    .el-tabs__item {
+      height: 32px;
+      line-height: 32px;
+    }
+  }
+}
+</style>

+ 30 - 5
src/view/layout/index.vue

@@ -8,7 +8,26 @@
       <template v-else>
         <ly-slide class="slide" :names="menuRouteNames" v-if="!hiddenSlide" />
         <div class="view" :class="{ full: hiddenSlide }">
-          <div class="main">
+          <div class="app-wrap m-4">
+            <div
+              class="app-scene"
+              ref="sceneRef"
+              :style="{
+                width: '100%',
+                height: 'calc(100% - 24px)',
+                // display: showScene ? 'none' : 'block'
+              }"
+            >
+            <!-- @load="setupSDK($event.target)" -->
+              <iframe
+                v-if="sceneURL"
+                :src="sceneURL"
+                frameborder="0"
+                :style="{ width: '100%', height: '100%' }"
+              ></iframe>
+            </div>
+          </div>
+          <div class="main p-4">
             <router-view v-slot="{ Component }">
               <component :is="Component" />
             </router-view>
@@ -23,8 +42,10 @@
 import lyTop from "./top/index.vue";
 import lySlide from "./slide/index.vue";
 import { routeIsSystem, router } from "@/router";
-import { computed } from "vue";
+import { computed, ref } from "vue";
 import { menuRouteNames } from "@/app";
+console.log(menuRouteNames, 'menuRouteNames');
+const sceneURL = ref('https://test.4dkankan.com/spg.html?m=KK-t-iN6cFCdwibf')
 
 const isSystem = computed(() => routeIsSystem());
 
@@ -60,24 +81,28 @@ const hiddenSlide = computed(
       flex: 0 0 auto;
       width: calc(100% - 16.66rem);
       background-color: var(--bgColor);
-      flex-direction: column;
+      // flex-direction: column;
       display: flex;
 
       &.full {
         width: 100%;
       }
-
+      .app-wrap, .app-view {
+        width: calc(100% - 320px);
+        height: 100%;
+      }
       .player {
         flex: 0 0 auto;
         height: 32px;
       }
 
       .main {
-        margin: 0 16px 16px;
+        margin: 0 0px 10px 0;
         display: flex;
         flex-direction: column;
         overflow: hidden;
         flex: 1;
+        background: #fff;
       }
     }
   }

+ 1 - 0
src/view/layout/slide/index.vue

@@ -22,6 +22,7 @@ import { router } from "@/router";
 const props = defineProps<{ names: string[] }>();
 
 const routes = getPermissionRoutes(props.names);
+console.log(routes, 'routes', props.names);
 </script>
 
 <style lang="scss" scoped>

+ 253 - 0
src/view/material/index.vue

@@ -0,0 +1,253 @@
+<template>
+  <div class="abstract">
+    <el-tabs v-model="activeName" class="demo-tabs h-full" @tab-click="handleClick">
+      <el-tab-pane label="现场图" name="1">
+        <div class="xct">
+          <el-button
+            style="width: calc(50% - 7px)"
+            type="primary"
+            @click="submitForm(ruleFormRef)"
+          >
+            绘制平面图
+          </el-button>
+          <el-button
+            style="width: calc(50% - 6px)"
+            type="primary"
+            @click="submitForm(ruleFormRef)"
+          >
+            AI 平面图
+          </el-button>
+          <el-button
+            class="w-full mt-4"
+            style="margin-left: 0"
+            type="primary"
+            @click="submitForm(ruleFormRef)"
+          >
+            绘制方位图
+          </el-button>
+          <div class="phote my-4">
+            <p class="pb-4">平面图</p>
+            <div class="pmt-phote w-full flex justify-between">
+              <div
+                class="phote-item"
+                style="width: calc(50% - 10px)"
+                v-for="(item, index) in srcList"
+                :key="index"
+              >
+                <el-image
+                  style="width: 100%; height: 100px"
+                  :src="item"
+                  :zoom-rate="1.2"
+                  :max-scale="7"
+                  :min-scale="0.2"
+                  :preview-src-list="srcList"
+                  preview-teleported
+                  :initial-index="index"
+                  fit="cover"
+                />
+                <div class="but flex justify-around">
+                  <el-icon :size="20"><Edit /></el-icon>
+                  <el-icon color="red" :size="20"><Delete /></el-icon>
+                </div>
+              </div>
+            </div>
+          </div>
+
+          <div class="phote my-4">
+            <p class="pb-4">方位图</p>
+            <div class="pmt-phote w-full flex justify-between">
+              <div
+                class="phote-item"
+                style="width: calc(50% - 10px)"
+                v-for="(item, index) in srcList"
+                :key="index"
+              >
+                <el-image
+                  style="width: 100%; height: 100px"
+                  :src="item"
+                  :zoom-rate="1.2"
+                  :max-scale="7"
+                  :min-scale="0.2"
+                  :preview-src-list="srcList"
+                  preview-teleported
+                  :initial-index="index"
+                  fit="cover"
+                />
+                <div class="but flex justify-around">
+                  <el-icon :size="20"><Edit /></el-icon>
+                  <el-icon color="red" :size="20"><Delete /></el-icon>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane class="h-full" label="现场照片" name="2">
+        <div class="scene relative h-full">
+          <el-button class="w-full" @click="handleAdd">上传</el-button>
+          <!-- <el-button class="w-full my-4"  style="margin-left: 0; margin-right: 0">添加场景</el-button> -->
+          <div class="scene-list">
+            <div
+              class="scene-title flex justify-between content-center py-4"
+              style="line-height: 14px"
+            >
+              <span>场景列表</span>
+              <span @click="settype = !settype">{{
+                settype ? "完成" : "修改分类"
+              }}</span>
+            </div>
+            <div class="list">
+              <div class="listItem py-2" v-for="item in 3" :key="itme">
+                <div class="title1">一级标题</div>
+                <div class="list2">
+                  <div class="title2">2级标题</div>
+
+                  <div
+                    class="item2 inline-block relative"
+                    v-for="(item2, index) in srcList"
+                    :key="index"
+                  >
+                    <el-icon
+                      :size="20"
+                      class="absolute z-1 cursor-pointer"
+                      style="right: -0px; top: -8px"
+                    >
+                      <CircleCloseFilled @click="handleDel" v-if="!settype" />
+                      <EditPen v-else />
+                    </el-icon>
+                    <el-image
+                      class="z-0 relative"
+                      :preview-src-list="srcList"
+                      preview-teleported
+                      :initial-index="index"
+                      style="width: 80px; height: 80px; margin-right: 10px"
+                      :src="item2"
+                      :fit="fit"
+                    />
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <el-button class="w-full absolute bottom-0" @click="handleAdd">照片制卷</el-button>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="勘验笔录" name="3">
+        <div class="blfrom">
+          <el-upload
+            class="upload-demo"
+            :multiple="false"
+            drag
+            :limit="1"
+            :disabled="!!file"
+            :before-upload="upload"
+            :file-list="fileList"
+            :http-request="() => {}"
+            :on-preview="previewFile"
+            :accept="accept"
+            :before-remove="removeFile"
+          >
+            <div type="primary" :disabled="!!file">
+              <div>点击或拖拽文件上传</div>
+              <div class="">支持 pdf、word 格式图片上传</div>
+            </div>
+          </el-upload>
+          <el-button class="w-full" @click="handleAdd">在线填写</el-button>
+        </div>
+        <div class="blList">
+          <div class="bllistItem flex justify-between items-center mt-2">
+            <div>点击或拖拽文件上传11</div>
+            <el-dropdown>
+              <el-icon>
+                <MoreFilled />
+              </el-icon>
+              <template #dropdown>
+                <el-dropdown-menu>
+                  <el-dropdown-item>编辑</el-dropdown-item>
+                  <el-dropdown-item>删除</el-dropdown-item>
+                  <el-dropdown-item>下载</el-dropdown-item>
+                </el-dropdown-menu>
+              </template>
+            </el-dropdown>
+          </div>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref, reactive } from "vue";
+import { addCaseFile } from "../originalPhoto/quisk";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { useUpload } from "@/hook/upload";
+import { Delete, Edit } from "@element-plus/icons-vue";
+const active = ref(true);
+const srcList = [
+  "https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg",
+  "https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg",
+];
+const settype = ref(false);
+const ruleFormRef = ref(null);
+const activeName = ref("1");
+const showModal = ref(false);
+const { size, fileList, upload, removeFile, previewFile, file, accept } =
+  useUpload({
+    maxSize: 10 * 1024 * 1024,
+    formats: [".word", ".pdf"],
+  });
+const handleClick = (tab) => {
+  console.log(tab);
+};
+const submitForm = async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log("submit!");
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+};
+const resetForm = (formEl) => {
+  if (!formEl) return;
+  formEl.resetFields();
+};
+function handleActive(params) {
+  console.log("handleActive", params);
+}
+async function handleAdd() {
+  await addCaseFile({ caseId: 2, fileType: 1 });
+  console.log("handleAdd");
+}
+function handleDel() {
+  ElMessageBox.confirm("确定删除?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    ElMessage({
+      type: "success",
+      message: "删除成功",
+    });
+  });
+}
+</script>
+<style lang="scss" scoped>
+.abstract {
+  height: 100%;
+  .el-form-item--label-top {
+    margin-bottom: 14px;
+  }
+  .form-content {
+    height: calc(100vh - 225px);
+    overflow-y: scroll;
+  }
+  .demo-tabs {
+    .el-tabs__item {
+      height: 32px;
+      line-height: 32px;
+    }
+  }
+}
+</style>

+ 141 - 0
src/view/originalPhoto/addCaseFile.vue

@@ -0,0 +1,141 @@
+<template>
+  <el-form
+    ref="form"
+    :model="caseFile"
+    label-width="90px"
+    class="camera-from dispatch-file-from jm-file-upload"
+  >
+    <el-form-item label="分类:" class="mandatory">
+      <el-cascader
+        v-model="caseFile.type"
+        :options="fileOptions"
+        :props="{
+          checkStrictly: true,
+        }"
+        clearable
+      />
+    </el-form-item>
+    <el-form-item label="文件:" class="mandatory uploadFile">
+      <el-upload
+        class="upload-demo"
+        :multiple="false"
+        drag
+        :limit="1"
+        :disabled="!!file"
+        :before-upload="upload"
+        :file-list="fileList"
+        :http-request="() => {}"
+        :on-preview="previewFile"
+        :accept="accept"
+        :before-remove="removeFile"
+      >
+        <div type="primary" :disabled="!!file">
+          <div>点击或拖拽文件上传</div>
+          <div class="">{{ size }}以内的{{ formatDesc }}</div>
+        </div>
+        <template v-slot:file="{ file }: { file: UploadFile }">
+          <div class="file" @click.stop="previewFile()">
+            <div>
+              <el-icon><Document /></el-icon>
+              <span class="name">{{ file.name }}</span>
+            </div>
+            <el-icon @click.stop="removeFile()"><Close /></el-icon>
+          </div>
+        </template>
+      </el-upload>
+      <el-button type="primary" class="mtk" @click="handleAdd"
+        >从媒体库上传</el-button
+      >
+    </el-form-item>
+  </el-form>
+</template>
+
+<script setup lang="ts">
+import {
+  DrawFormatDesc,
+  DrawFormats,
+  FileDrawType,
+  OtherFormatDesc,
+  OtherFormats,
+  fileOptions
+} from "@/constant/caseFile";
+import { maxFileSize } from "@/constant/caseFile";
+import { useUpload } from "@/hook/upload";
+import { CaseFile, addCaseFile } from "@/store/caseFile";
+import { ElMessage, UploadFile } from "element-plus";
+import { computed, ref, watchEffect } from "vue";
+import { addCaseScenes } from "./quisk";
+import { QuiskExpose } from "@/helper/mount";
+
+const props = defineProps<{
+  caseId: number;
+  fileType: number;
+}>();
+
+const caseFile = ref({
+  caseId: props.caseId,
+  filesTypeId: props.fileType,
+  filesTitle: "",
+  type: '',
+});
+
+const { size, fileList, upload, removeFile, previewFile, file, accept } = useUpload({
+  maxSize: 10 * 1024 * 1024,
+  formats: [".jpg", ".jpeg", ".png", '.mp4'],
+});
+
+const formatDesc = computed(() =>
+  'jpg、png、jpeg、mp4上传'
+);
+
+const handleAdd = async () => {
+  await addCaseScenes();
+};
+watchEffect(() => {
+  if (file.value?.name) {
+    caseFile.value.filesTitle = file.value?.name.substring(0, 50);
+  }
+});
+
+defineExpose<QuiskExpose>({
+  async submit() {
+    if (!file.value) {
+      ElMessage.error("请上传附件");
+      throw "请上传附件";
+    } else if (!caseFile.value.filesTitle.trim()) {
+      ElMessage.error("附件标题不能为空!");
+      throw "附件标题不能为空!";
+    }
+
+    await addCaseFile({ ...caseFile.value, file: file.value });
+    return caseFile.value;
+  },
+});
+</script>
+
+<style scoped lang="scss">
+.upload-demo {
+  overflow: hidden;
+}
+
+.file {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  > div {
+    display: flex;
+    align-items: center;
+  }
+
+  .name {
+    margin-left: 10px;
+  }
+}
+.jm-file-upload {
+  .mtk {
+    position: absolute;
+    right: 0;
+    top: 0;
+  }
+}
+</style>

+ 111 - 0
src/view/originalPhoto/addScenes.vue

@@ -0,0 +1,111 @@
+<template>
+  <VRModelList :params="params">
+    <template v-slot:header>
+      <el-form-item label="名称:" style="grid-area: 1 / 1 / 2 / 4">
+        <el-input v-model="params.keyword" placeholder="请输入" />
+      </el-form-item>
+      <el-form-item label="分组:" style="grid-area: 1 / 1 / 2 / 4">
+        <el-input v-model="params.keyword" placeholder="请输入" />
+      </el-form-item>
+    </template>
+    <template v-slot:content>
+      <el-table
+        :data="params.pagging.state.table.rows"
+        tooltip-effect="dark"
+        ref="tableRef"
+        style="width: 100%"
+        size="large"
+        @selection-change="changeSelection"
+      >
+        <el-table-column type="selection" width="50" />
+        <el-table-column label="名称" v-slot:default="{ row }">
+          {{ params.isSwmx ? row.modelTitle : row.name }}
+        </el-table-column>
+        <el-table-column label="格式" prop="deptName"></el-table-column>
+        <el-table-column label="大小" prop="modelDateType" v-if="params.isSwmx" />
+        <el-table-column label="分组" prop="createTime" v-slot:default="{ row }">
+          {{ row.createTime.substr(0, 16) }}
+        </el-table-column>
+        <el-table-column
+        label="操作"
+        v-slot:default="{ row }"
+        :width="240"
+      >
+        <span
+          class="oper-span"
+          @click="del(row)"
+          style="color: var(--primaryColor)"
+          v-pdpath="['del']"
+        >
+          删除
+        </span>
+      </el-table-column>
+      </el-table>
+    </template>
+  </VRModelList>
+</template>
+
+<script setup lang="ts">
+import VRModelList from "./list.vue";
+import { Scene } from "@/store/scene";
+import { CaseScenes } from "@/store/case";
+import { useScenePaggingParams } from "@/view/vrmodel/pagging";
+import { onMounted, ref, watch, watchEffect } from "vue";
+import {
+  getCaseSceneList,
+  getCaseScenes,
+  getSceneKey,
+  replaceCaseScenes,
+} from "@/store/case";
+import { QuiskExpose } from "@/helper/mount";
+import { ElTable } from "element-plus";
+
+const props = defineProps<{ caseId: number }>();
+const params = useScenePaggingParams();
+const caseScenes = ref<CaseScenes>(getCaseScenes([]));
+const tableRef = ref<InstanceType<typeof ElTable>>();
+// const 
+watch(
+  () => params.pagging.state.query,
+  () => {
+    params.pagging.state.query.status = 2;
+    params.pagging.state.query.caseId = props.caseId;
+  },
+  { immediate: true, deep: true }
+);
+// 复选框同步
+watchEffect(() => {
+  if (!tableRef.value) return;
+  const selectKeys = caseScenes.value.find(
+    (item) => item.type === params.pagging.state.query.type
+  )!.numList;
+
+  params.pagging.state.table.rows.forEach((scene) => {
+    tableRef.value!.toggleRowSelection(scene, selectKeys.includes(getSceneKey(scene)));
+  });
+});
+
+const changeSelection = (selectScenes: Scene[]) => {
+  if (params.pagging.loading) return;
+  const pagScenes = params.pagging.state.table.rows;
+  const type = params.pagging.state.query.type;
+  const typeCaseScenes = caseScenes.value.find((item) => item.type === type)!;
+  const oldKeys = caseScenes.value.find((item) => item.type === type)!.numList;
+  const selectKeys = selectScenes.map(getSceneKey);
+  const pagKeys = pagScenes.map(getSceneKey);
+
+  typeCaseScenes.numList = oldKeys
+    // 保留其他页的key,剔除当前页的key
+    .filter((key) => !pagKeys.includes(key))
+    // 拼接上当前页选中的key
+    .concat(selectKeys);
+};
+// 初始化数据
+onMounted(async () => {
+  caseScenes.value = getCaseScenes(await getCaseSceneList(props.caseId));
+});
+
+defineExpose<QuiskExpose>({
+  submit: () => replaceCaseScenes(props.caseId, caseScenes.value),
+});
+</script>

+ 48 - 0
src/view/originalPhoto/index.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="scene">
+    <el-button class="w-full" @click="handleAdd">上传</el-button>
+    <!-- <el-button class="w-full my-4"  style="margin-left: 0; margin-right: 0">添加场景</el-button> -->
+    <div class="scene-list">
+      <div class="scene-title flex justify-between content-center py-4" style="line-height: 14px">
+        <span >场景列表</span>
+        <span  @click="settype = !settype">{{settype?'完成':'修改分类'}}</span>
+      </div>
+      <div class="list">
+        <div
+          class="listItem py-2"
+          v-for="item in 3"
+          :key="itme"
+        >
+          <div class="title1">一级标题</div>
+          <div class="list2">
+          <div class="title2">2级标题</div>
+          
+          <div class="item2 inline-block relative" v-for="(item2, index) in srcList" :key="index">
+            <el-icon :size="20" class="absolute z-1 cursor-pointer" style="right: -0px; top: -8px">
+              <CircleCloseFilled v-if="!settype" />
+              <EditPen v-else />
+            </el-icon>
+            <el-image class="z-0 relative" preview-teleported :preview-src-list="srcList" :initial-index="index" style="width: 80px; height: 80px;margin-right: 10px" :src="item2" :fit="fit" />
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref } from "vue";
+import { addCaseFile } from "./quisk";
+const active = ref(true);
+const settype = ref(false);
+const showModal = ref(false);
+const srcList = ["https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg","https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"]
+function handleActive(params) {
+  console.log("handleActive", params);
+}
+async function handleAdd() {
+  await addCaseFile({ caseId: 2, fileType: 1 });
+  console.log("handleAdd");
+}
+</script>

+ 43 - 0
src/view/originalPhoto/list.vue

@@ -0,0 +1,43 @@
+<template>
+    <el-form label-width="84px" inline>
+      <slot name="header" />
+      <el-form-item class="searh-btns" style="grid-area: 1 / 4 / 2 / 4">
+        <el-button type="primary" @click="params.pagging.refresh">查询</el-button>
+        <el-button type="primary" plain @click="params.pagging.queryReset"
+          >重置</el-button
+        >
+        <el-button type="primary" @click="params.pagging.refresh">上传文件</el-button>
+      </el-form-item>
+    </el-form>
+
+  <div class="body-layer">
+    <slot name="content" />
+    <com-pagination
+      @size-change="params.pagging.changPageSize"
+      @current-change="params.pagging.changPageCurrent"
+      :current-page="params.pagging.state.pag.currentPage"
+      :page-size="params.pagging.state.pag.size"
+      :total="params.pagging.state.pag.total"
+    />
+  </div>
+</template>
+
+<script setup lang="ts">
+import comHead from "@/components/head/index.vue";
+import comPagination from "@/components/pagination/index.vue";
+import { SceneType } from "@/store/scene";
+import { SceneTypeDesc } from "@/constant/scene";
+import { useScenePaggingParams } from "./pagging";
+
+defineProps<{ params: ReturnType<typeof useScenePaggingParams> }>();
+
+const headOptions = [
+  { value: SceneType.SWKK, name: SceneTypeDesc[SceneType.SWKK] },
+  { value: SceneType.SWKJ, name: SceneTypeDesc[SceneType.SWKJ] },
+  { value: SceneType.SWSS, name: SceneTypeDesc[SceneType.SWSS] },
+  { value: SceneType.SWSSMX, name: SceneTypeDesc[SceneType.SWSSMX] },
+  { value: SceneType.SWYDSS, name: SceneTypeDesc[SceneType.SWYDSS] },
+  { value: SceneType.SWYDMX, name: SceneTypeDesc[SceneType.SWYDMX] },
+  { value: SceneType.SWMX, name: SceneTypeDesc[SceneType.SWMX] },
+];
+</script>

+ 56 - 0
src/view/originalPhoto/pagging.ts

@@ -0,0 +1,56 @@
+import { usePagging } from "@/hook/pagging";
+import { SceneType, getScenePagging } from "@/store/scene";
+import { computed, reactive, watch, watchEffect } from "vue";
+
+export const useScenePaggingParams = () => {
+  const pagging = usePagging({
+    get: getScenePagging,
+    paramsTemlate: {
+      type: SceneType.SWKK,
+      sceneName: "",
+      modelTitle: "",
+      deptId: "",
+      snCode: "",
+      sceneType: '1',
+    },
+  });
+
+  const isSwmx = computed(() => pagging.state.query.type === SceneType.SWMX);
+  const keyword = computed({
+    get: () =>
+      isSwmx.value
+        ? pagging.state.query.modelTitle
+        : pagging.state.query.sceneName,
+    set: (val: string) => {
+      pagging.state.query.modelTitle = val;
+      pagging.state.query.sceneName = val;
+    },
+  });
+
+  let oldSnCode = pagging.state.query.snCode;
+  watchEffect(() => {
+    if (isSwmx.value) {
+      oldSnCode = pagging.state.query.snCode;
+      pagging.state.query.snCode = "";
+    } else {
+      pagging.state.query.snCode = oldSnCode;
+    }
+  });
+
+  watch(
+    () => pagging.state.query.type,
+    () => {
+      pagging.state.pag.currentPage = 1;
+    }
+  );
+
+  const queryResetRaw = pagging.queryReset;
+  pagging.queryReset = () => {
+    const type = pagging.state.query.type;
+    queryResetRaw();
+    pagging.state.query.type = type;
+  };
+
+  return reactive({ pagging, keyword, isSwmx });
+};
+export type ScenePagging = ReturnType<typeof useScenePaggingParams>["pagging"];

+ 20 - 0
src/view/originalPhoto/quisk.ts

@@ -0,0 +1,20 @@
+import AddCaseFile from "./addCaseFile.vue";
+import AddScenes from "./addScenes.vue";
+import setType from "./setType.vue";
+import { quiskMountFactory } from "@/helper/mount";
+import { nextTick } from "vue";
+
+export const addCaseFile = quiskMountFactory(AddCaseFile, {
+  title: "上传附件",
+  width: 550,
+});
+
+export const addCaseScenes = quiskMountFactory(AddScenes, {
+  title: "媒体库",
+  width: 1000,
+});
+
+export const setTypeFile = quiskMountFactory(setType, {
+  title: "修改分类",
+  width: 550,
+});

+ 109 - 0
src/view/originalPhoto/setType.vue

@@ -0,0 +1,109 @@
+<template>
+  <el-form
+    ref="form"
+    :model="caseFile"
+    label-width="90px"
+    class="camera-from dispatch-file-from jm-file-upload"
+  >
+    <el-form-item label="分类:" class="mandatory">
+      <el-cascader
+        v-model="caseFile.type"
+        :options="fileOptions"
+        :props="{
+          checkStrictly: true,
+        }"
+        clearable
+      />
+    </el-form-item>
+  </el-form>
+</template>
+
+<script setup lang="ts">
+import {
+  DrawFormatDesc,
+  DrawFormats,
+  FileDrawType,
+  OtherFormatDesc,
+  OtherFormats,
+  fileOptions
+} from "@/constant/caseFile";
+import { maxFileSize } from "@/constant/caseFile";
+import { useUpload } from "@/hook/upload";
+import { CaseFile, addCaseFile } from "@/store/caseFile";
+import { ElMessage, UploadFile } from "element-plus";
+import { computed, ref, watchEffect } from "vue";
+import { addCaseScenes } from "./quisk";
+import { QuiskExpose } from "@/helper/mount";
+
+const props = defineProps<{
+  caseId: number;
+  fileType: number;
+}>();
+
+const caseFile = ref({
+  caseId: props.caseId,
+  filesTypeId: props.fileType,
+  filesTitle: "",
+  type: '',
+});
+
+const { size, fileList, upload, removeFile, previewFile, file, accept } = useUpload({
+  maxSize: 10 * 1024 * 1024,
+  formats: [".jpg", ".jpeg", ".png", '.mp4'],
+});
+
+const formatDesc = computed(() =>
+  'jpg、png、jpeg、mp4上传'
+);
+
+const handleAdd = async () => {
+  await addCaseScenes();
+};
+watchEffect(() => {
+  if (file.value?.name) {
+    caseFile.value.filesTitle = file.value?.name.substring(0, 50);
+  }
+});
+
+defineExpose<QuiskExpose>({
+  async submit() {
+    if (!file.value) {
+      ElMessage.error("请上传附件");
+      throw "请上传附件";
+    } else if (!caseFile.value.filesTitle.trim()) {
+      ElMessage.error("附件标题不能为空!");
+      throw "附件标题不能为空!";
+    }
+
+    await addCaseFile({ ...caseFile.value, file: file.value });
+    return caseFile.value;
+  },
+});
+</script>
+
+<style scoped lang="scss">
+.upload-demo {
+  overflow: hidden;
+}
+
+.file {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  > div {
+    display: flex;
+    align-items: center;
+  }
+
+  .name {
+    margin-left: 10px;
+  }
+}
+.jm-file-upload {
+  .mtk {
+    position: absolute;
+    right: 0;
+    top: 0;
+  }
+}
+</style>

+ 154 - 0
src/view/other/index.vue

@@ -0,0 +1,154 @@
+<template>
+  <div class="abstract">
+    <div class="blfrom">
+      <div class="fromTitle">侦查实验</div>
+      <el-upload
+        class="upload-demo"
+        :multiple="false"
+        drag
+        :limit="1"
+        :disabled="!!file"
+        :before-upload="upload"
+        :file-list="fileList"
+        :http-request="() => {}"
+        :on-preview="previewFile"
+        :accept="accept"
+        :before-remove="removeFile"
+      >
+        <div type="primary" :disabled="!!file">
+          <div>点击或拖拽文件上传</div>
+          <div class="">支持 pdf、word 格式图片上传</div>
+        </div>
+      </el-upload>
+    </div>
+    <div class="blfrom">
+      <div class="fromTitle">其他材料</div>
+      <el-upload
+        class="upload-demo"
+        :multiple="false"
+        drag
+        :limit="1"
+        :disabled="!!file"
+        :before-upload="upload"
+        :file-list="fileList"
+        :http-request="() => {}"
+        :on-preview="previewFile"
+        :accept="accept"
+        :before-remove="removeFile"
+      >
+        <div type="primary" :disabled="!!file">
+          <div>点击或拖拽文件上传</div>
+          <div class="">支持 pdf、word 格式图片上传</div>
+        </div>
+      </el-upload>
+    </div>
+    <div class="blList">
+
+      <div class="listItem py-2" v-for="item in 3" :key="itme">
+                <div class="title1">一级标题</div>
+                <div class="list2">
+                  <div class="title2">2级标题</div>
+
+                  <div
+                    class="item2 inline-block relative"
+                    v-for="(item2, index) in srcList"
+                    :key="index"
+                  >
+                    <el-icon
+                      :size="20"
+                      class="absolute z-1 cursor-pointer"
+                      style="right: -0px; top: -8px"
+                    >
+                      <CircleCloseFilled @click="handleDel" />
+                    </el-icon>
+                    <el-image
+                      class="z-0 relative"
+                      :preview-src-list="srcList"
+                      preview-teleported
+                      :initial-index="index"
+                      style="width: 80px; height: 80px; margin-right: 10px"
+                      :src="item2"
+                      :fit="fit"
+                    />
+                  </div>
+                </div>
+              </div>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { computed, ref, reactive } from "vue";
+import { addCaseFile } from "../originalPhoto/quisk";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { useUpload } from "@/hook/upload";
+import { Delete, Edit } from "@element-plus/icons-vue";
+const active = ref(true);
+const srcList = [
+  "https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg",
+  "https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg",
+];
+const settype = ref(false);
+const ruleFormRef = ref(null);
+const activeName = ref("1");
+const showModal = ref(false);
+const { size, fileList, upload, removeFile, previewFile, file, accept } =
+  useUpload({
+    maxSize: 10 * 1024 * 1024,
+    formats: [".word", ".pdf"],
+  });
+const handleClick = (tab) => {
+  console.log(tab);
+};
+const submitForm = async (formEl) => {
+  if (!formEl) return;
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      console.log("submit!");
+    } else {
+      console.log("error submit!", fields);
+    }
+  });
+};
+const resetForm = (formEl) => {
+  if (!formEl) return;
+  formEl.resetFields();
+};
+function handleActive(params) {
+  console.log("handleActive", params);
+}
+async function handleAdd() {
+  await addCaseFile({ caseId: 2, fileType: 1 });
+  console.log("handleAdd");
+}
+function handleDel() {
+  ElMessageBox.confirm("确定删除?", "提示", {
+    confirmButtonText: "确定",
+    cancelButtonText: "取消",
+    type: "warning",
+  }).then(() => {
+    ElMessage({
+      type: "success",
+      message: "删除成功",
+    });
+  });
+}
+</script>
+<style lang="scss" scoped>
+.abstract {
+  height: 100%;
+  .el-form-item--label-top {
+    margin-bottom: 14px;
+  }
+  .form-content {
+    height: calc(100vh - 225px);
+    overflow-y: scroll;
+  }
+  .demo-tabs {
+    .el-tabs__item {
+      height: 32px;
+      line-height: 32px;
+    }
+  }
+}
+</style>

+ 1 - 1
src/view/system/login.vue

@@ -145,7 +145,7 @@ const submitClick = async () => {
       url.searchParams.append("token", user.value.token);
       window.location.replace(url);
     } else {
-      router.replace({ name: RouteName.scene });
+      router.replace({ name: RouteName.scene, params: { caseId: 360 } });
     }
   } catch (e) {
     console.error(e);

+ 34 - 21
src/view/vrmodel/index.vue

@@ -1,23 +1,24 @@
 <template>
-  <List :params="params">
-    <template v-slot:header>
-      <el-form-item label="所属架构:">
-        <com-select v-model="params.pagging.state.query.deptId" />
-      </el-form-item>
-      <el-form-item label="S/N码:" v-if="!params.isSwmx">
-        <el-input
-          v-model="params.pagging.state.query.snCode"
-          placeholder="请输入"
-        ></el-input>
-      </el-form-item>
-      <el-form-item label="标题:">
-        <el-input v-model="params.keyword" placeholder="请输入"></el-input>
-      </el-form-item>
-    </template>
-    <template v-slot:content>
-      <component :is="component" :pagging="params.pagging" />
-    </template>
-  </List>
+  <div class="scene">
+    <el-button class="w-full">创建多元融合</el-button>
+    <el-button class="w-full my-4" @click="handleAdd" style="margin-left: 0; margin-right: 0">添加场景</el-button>
+    <div class="scene-list">
+        <div class="scene-title flex justify-between content-center">
+          <span style="line-height: 32px">场景列表</span>
+          <el-switch v-model="active" @change="handleActive" />
+        </div>
+        <div class="list" v-if="active">
+          <div
+            class="listItem flex justify-between py-2"
+            v-for="item in 3"
+            :key="itme"
+          >
+            <span>场景列表{{ item }}</span>
+            <div quaternary type="primary">编辑</div>
+          </div>
+        </div>
+      </div>
+  </div>
 </template>
 
 <script setup lang="ts">
@@ -26,8 +27,20 @@ import List from "./list.vue";
 import SceneContent from "./sceneContent.vue";
 import ModelContent from "./modelContent.vue";
 import { useScenePaggingParams } from "./pagging";
-import { computed } from "vue";
-
+import { computed, ref } from "vue";
+import { tableModelScene } from "./quisk";
+const active = ref(true);
+const showModal = ref(false);
 const params = useScenePaggingParams();
 const component = computed(() => (params.isSwmx ? ModelContent : SceneContent));
+function handleActive(params) {
+  console.log("handleActive", params);
+}
+async function handleAdd() {
+  console.log("handleAdd");
+  if (await tableModelScene({})) {
+    console.log("刷新列表");
+  }
+
+}
 </script>

+ 0 - 2
src/view/vrmodel/modelContent.vue

@@ -1,7 +1,5 @@
 <template>
   <div class="body-head">
-    <h3 style="visibility: hidden">场景管理</h3>
-
     <el-tooltip
       class="item"
       effect="dark"

+ 1 - 0
src/view/vrmodel/pagging.ts

@@ -11,6 +11,7 @@ export const useScenePaggingParams = () => {
       modelTitle: "",
       deptId: "",
       snCode: "",
+      sceneType: '1',
     },
   });
 

+ 5 - 1
src/view/vrmodel/quisk.ts

@@ -1,5 +1,6 @@
 import { QuoteScene, SceneType } from "@/store/scene";
 import EditModel from "./editModel.vue";
+import tableModel from "./tableModel.vue";
 import SceneDownload from "./sceneDownload.vue";
 import { quiskMountFactory } from "@/helper/mount";
 import { axios, checkHasDownload } from "@/request";
@@ -8,7 +9,10 @@ export const editModelScene = quiskMountFactory(EditModel, {
   title: "编辑模型",
   width: 500,
 });
-
+export const tableModelScene = quiskMountFactory(tableModel, {
+  title: "添加场景",
+  width: 1000,
+});
 export type SceneDpwnloadProps = { scene: QuoteScene };
 export const sceneDownload = async(props: SceneDpwnloadProps) => {
   const params = {

+ 16 - 8
src/view/vrmodel/sceneContent.vue

@@ -1,21 +1,24 @@
 <template>
   <div class="body-head">
-    <h3 style="visibility: hidden">场景管理</h3>
+    <!-- <h3 style="visibility: hidden">场景管理</h3> -->
   </div>
 
   <el-table
+    class="mybody-head"
     :data="pagging.state.table.rows"
     tooltip-effect="dark"
-    style="width: 100%"
+    style="width: 100%;height: 250px;"
+    :height="250"
     size="large"
   >
     <!-- -1 计算失败  0 计算中 1 计算成功并可以外网访问,不能编辑 2计算成功只能内网,能编辑 -->
-    <el-table-column label="序号" width="70" v-slot:default="{ $index }">
+    <el-table-column type="selection" width="55" />
+    <!-- <el-table-column label="序号" width="70" v-slot:default="{ $index }">
       <div style="text-align: center">
         {{ pagging.state.pag.size * (pagging.state.pag.currentPage - 1) + $index + 1 }}
       </div>
-    </el-table-column>
-    <el-table-column label="场景标题" prop="name"></el-table-column>
+    </el-table-column> -->
+    <el-table-column label="场景标题11" prop="name"></el-table-column>
     <el-table-column label="S/N码" prop="snCode"></el-table-column>
     <!-- <el-table-column label="浏览数量" prop="viewCount"></el-table-column> -->
     <el-table-column label="拍摄时间" prop="createTime" v-slot:default="{ row }">
@@ -24,8 +27,8 @@
     <el-table-column label="状态" v-slot:default="{ row }: { row: QuoteScene }">
       {{ QuoteSceneStatusDesc[row.status] }}
     </el-table-column>
-    <el-table-column label="所属架构" prop="deptName"></el-table-column>
-    <el-table-column label="操作" v-slot:default="{ row }: { row: QuoteScene }">
+    <!-- <el-table-column label="所属架构" prop="deptName"></el-table-column> -->
+    <!-- <el-table-column label="操作" v-slot:default="{ row }: { row: QuoteScene }">
       <span
         class="oper-span"
         v-pdpath="['view']"
@@ -75,7 +78,7 @@
       >
         下载
       </span>
-    </el-table-column>
+    </el-table-column> -->
   </el-table>
 </template>
 
@@ -105,3 +108,8 @@ const sceneDownloadHandler = (scene: QuoteScene) => {
   sceneDownload({ scene });
 };
 </script>
+<style scoped lang="scss">
+.mybody-head{
+    flex: auto !important;
+}
+</style>

+ 50 - 0
src/view/vrmodel/tableModel.vue

@@ -0,0 +1,50 @@
+<template>
+  <List :params="params">
+    <template v-slot:header>
+      <el-form-item label="场景名称:" style="width: 250px">
+        <el-input v-model="params.keyword" placeholder="请输入"></el-input>
+      </el-form-item>
+      <el-form-item label="类型:" style="width: 250px">
+        <el-select
+          v-model="params.pagging.state.query.sceneType"
+          placeholder="Select"
+          size="large"
+          style="width: 240px"
+        >
+      <el-option
+        v-for="item in options"
+        :key="item.value"
+        :label="item.label"
+        :value="item.value"
+      />
+    </el-select>
+        <!-- <com-select v-model="params.pagging.state.query.deptId" /> -->
+      </el-form-item>
+    </template>
+    <template v-slot:content>
+      <component :is="component" :pagging="params.pagging" />
+    </template>
+  </List>
+</template>
+
+<script setup lang="ts">
+import comSelect from "@/components/company-select/index.vue";
+import List from "./list.vue";
+import SceneContent from "./sceneContent.vue";
+import ModelContent from "./modelContent.vue";
+import { useScenePaggingParams } from "./pagging";
+import { computed } from "vue";
+const options = [
+  {
+    value: '1',
+    label: 'Mesh 场景',
+  },
+  {
+    value: '2',
+    label: '点云场景',
+  },
+]
+
+const params = useScenePaggingParams();
+const component = computed(() => (params.isSwmx ? ModelContent : SceneContent));
+</script>

+ 2 - 0
vite.config.ts

@@ -2,6 +2,7 @@ import { defineConfig } from "vite";
 import vue from "@vitejs/plugin-vue";
 import { resolve } from "path";
 import ElementPlus from "unplugin-element-plus/vite";
+import WindiCSS from 'vite-plugin-windicss'
 
 let app = "criminal";
 if (process.argv.length > 3) {
@@ -35,6 +36,7 @@ export default defineConfig({
   },
   plugins: [
     vue(),
+    WindiCSS(),
     ElementPlus({
       useSource: true,
     }),

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1293 - 0
yarn.lock