bill 1 éve
szülő
commit
a417fc7718

+ 3 - 1
src/app/criminal/view/example/index.vue

@@ -40,7 +40,9 @@
       >
         <CaseEditMenu
           :caseId="row.caseId"
-          :menus="[{ key: 'edit', label: '编辑案件', onClick: () => editHandler(row) }]"
+          :prevMenu="[
+            { key: 'edit', label: '编辑案件', onClick: () => editHandler(row) },
+          ]"
           v-if="row.caseId"
         />
         <span class="oper-span" @click="gotoQuery(row.caseId)">查看</span>

+ 1 - 0
src/app/fire/view/dispatch/editFire.vue

@@ -125,3 +125,4 @@ defineExpose<QuiskExpose>({
   },
 });
 </script>
+@/hook/helper/cascader@/helper/mount

+ 1 - 0
src/app/fire/view/dispatch/header.vue

@@ -86,3 +86,4 @@ watchEffect(
 
 const fireReason = genCascaderValue(ref(props.pagging.state.query), "fireReason");
 </script>
+@/hook/helper/cascader

+ 1 - 1
src/app/fire/view/dispatch/index.vue

@@ -129,4 +129,4 @@ const editHandler = async (row: Fire) => {
 const addHandler = async () => {
   (await addFire({})) && pagging.refresh();
 };
-</script>
+</script>

+ 1 - 1
src/constant/scene.ts

@@ -18,7 +18,7 @@ export const SceneTypeDomain: { [key in SceneType]: string } = {
 };
 
 export const SceneTypePaths: { [key in SceneType]: string[] } = {
-  [SceneType.SWKK]: ["/swkk/spg.html", "/swkk/epg.html"],
+  [SceneType.SWKK]: ["/swkk/spg.html", "/swkk/epg.html", "/swkk/livestream"],
   [SceneType.SWKJ]: ["/swkk/spg.html", "/swkk/epg.html"],
   [SceneType.SWSS]: ["/swss/index.html", "/swss/index.html"],
   [SceneType.SWMX]: import.meta.env.DEV

+ 6 - 0
src/hook/pagging.ts

@@ -6,6 +6,7 @@ import {
   reactive,
   isReactive,
   Ref,
+  nextTick,
 } from "vue";
 import { UN_REQ_NUM } from "@/constant/sys";
 import { dateFormat, mix, throttle } from "@/util";
@@ -79,8 +80,10 @@ export const usePagging = <PARAM, RAW, NRAW>(
   const tableOperate = genTableOperate<RAW>();
   const pagOperate = genPagOperate();
   const queryOperate = genQueryOperate(props.paramsTemlate);
+  const loading = ref(false);
 
   const refreshRaw = async () => {
+    loading.value = true;
     const pag = pagOperate.pagStore.value;
     const paramsRaw = {
       ...queryOperate.paramsStore.value,
@@ -102,6 +105,8 @@ export const usePagging = <PARAM, RAW, NRAW>(
 
     pag.total = data.total;
     tableOperate.tableState.value.rows = data.list as any;
+    await nextTick();
+    loading.value = false;
   };
 
   const refresh = throttle(refreshRaw, 300);
@@ -172,6 +177,7 @@ export const usePagging = <PARAM, RAW, NRAW>(
       refresh();
     },
     state,
+    loading,
     add: itemAPI.add,
     set: itemAPI.set,
     changeSelectRows: tableOperate.changeSelectRows,

+ 1 - 0
src/request/urls.ts

@@ -90,6 +90,7 @@ export const deleteExample = "/fusion/case/delete";
 // 获取case场景列表
 export const caseSceneList = `/fusion/case/sceneList`;
 export const repCaseScenes = `/fusion/case/addScene`;
+export const syncInfo = `/fusion/caseLive/getTakeLookRoom`;
 
 // 获取caseTaggings
 export const caseTaggingList = `/fusion/caseTag/allList`;

+ 5 - 0
src/store/case.ts

@@ -5,6 +5,7 @@ import {
   getCasePsw,
   repCaseScenes,
   setCasePsw,
+  syncInfo,
 } from "@/request";
 import { ModelScene, QuoteScene, Scene, SceneType } from "./scene";
 
@@ -30,6 +31,10 @@ export const getCaseSceneList = async (caseId: number): Promise<Scene[]> => {
   return (await axios.get(caseSceneList, { params: { caseId } })).data;
 };
 
+export const getSyncSceneInfo = async (caseId: number) => {
+  return (await axios.post<string>(syncInfo, { caseId })).data;
+};
+
 export const getSceneKey = (scene: Scene) =>
   scene.type === SceneType.SWMX
     ? (scene as ModelScene).modelId

+ 1 - 0
src/store/scene.ts

@@ -109,6 +109,7 @@ type ScenePaggingParams = PaggingReq<
   Pick<BaseScene, "type"> & {
     modelTitle: string;
     sceneName: string;
+    status?: number;
   }
 >;
 export const getScenePagging = async (params: ScenePaggingParams) => {

+ 18 - 0
src/util/index.ts

@@ -293,3 +293,21 @@ export const mixEnum = <T, K>(enum1: T, enum2: K): T | K => {
     ...enum2,
   };
 };
+
+// 字符串转params对象
+export const strToParams = (str: string) => {
+  if (str[0] === "?") {
+    str = str.substr(1);
+  }
+
+  const result: { [key: string]: string } = {};
+  const splitRG = /([^=&]+)(?:=([^&]*))?&?/;
+
+  let rgRet;
+  while ((rgRet = str.match(splitRG))) {
+    result[rgRet[1]] = rgRet[2] === undefined ? "" : rgRet[2];
+    str = str.substr(rgRet[0].length);
+  }
+
+  return result;
+};

+ 26 - 4
src/view/case/addScenes.vue

@@ -37,7 +37,7 @@ import VRModel from "@/view/vrmodel/index.vue";
 import { Scene, SceneType } from "@/store/scene";
 import { CaseScenes } from "@/store/case";
 import { ScenePagging } from "@/view/vrmodel/pagging";
-import { onMounted, onUnmounted, ref, watchEffect } from "vue";
+import { Ref, onMounted, onUnmounted, ref, watchEffect } from "vue";
 import {
   getCaseSceneList,
   getCaseScenes,
@@ -51,18 +51,32 @@ const props = defineProps<{ caseId: number }>();
 
 const caseScenes = ref<CaseScenes>(getCaseScenes([]));
 const tableRef = ref<InstanceType<typeof ElTable>>();
+let paggingLoading: Ref<boolean>;
 // 同步table选择
 let stopSyncWatch: () => void;
 const syncTableSelects = (pagging: ScenePagging) => {
   stopSyncWatch && stopSyncWatch();
-  stopSyncWatch = watchEffect(
+
+  const stopParamWatch = watchEffect(
     () => {
+      if (pagging.state.query.type === SceneType.SWMX) {
+        pagging.state.query.status = 2;
+      } else {
+        delete pagging.state.query.status;
+      }
+    },
+    { flush: "sync" }
+  );
+  const stopSyncSelect = watchEffect(
+    () => {
+      paggingLoading = pagging.loading;
+      if (paggingLoading.value) {
+        return;
+      }
       const selectKeys = caseScenes.value.find(
         (item) => item.type === pagging.state.query.type
       )!.numList;
-      console.log(pagging.state.table.rows);
       pagging.state.table.rows.forEach((scene) => {
-        console.log(selectKeys.includes(getSceneKey(scene)));
         tableRef.value?.toggleRowSelection(
           scene,
           selectKeys.includes(getSceneKey(scene))
@@ -71,8 +85,16 @@ const syncTableSelects = (pagging: ScenePagging) => {
     },
     { flush: "post" }
   );
+
+  stopSyncWatch = () => {
+    stopSyncSelect();
+    stopParamWatch();
+  };
 };
 const changeSelection = (selectScenes: Scene[], pagScenes: Scene[], type: SceneType) => {
+  if (paggingLoading.value) {
+    return;
+  }
   const typeCaseScenes = caseScenes.value.find((item) => item.type === type)!;
   const oldKeys = caseScenes.value.find((item) => item.type === type)!.numList;
   const selectKeys = selectScenes.map(getSceneKey);

+ 1 - 1
src/view/case/caseFile.vue

@@ -104,4 +104,4 @@ onMounted(async () => {
   console.log(types.value);
   currentTypeId.value = types.value[0].filesTypeId;
 });
-</script>
+</script>

+ 1 - 1
src/view/case/draw/slider.vue

@@ -68,7 +68,7 @@ const emit = defineEmits<{
 
 const { percentage, upload, file, removeFile } = useUpload({
   maxSize: maxFileSize,
-  formats: OtherFormats,
+  formats: [".jpg", ".jpeg", ".png", ".svg"],
 });
 
 watchEffect(async () => {

+ 14 - 2
src/view/case/editMenu.vue

@@ -18,9 +18,13 @@
 
 <script setup lang="ts">
 import { computed } from "vue";
-import { getFuseCodeLink, checkScenesOpen, MenuItem } from "./help";
+import { getFuseCodeLink, checkScenesOpen, MenuItem, getSWKKSyncLink } from "./help";
 import { showCaseScenes, addCaseScenes } from "./quisk";
 import { RouteName, router } from "@/router";
+import { getCaseSceneList } from "@/store/case";
+import { SceneType } from "@/store/scene";
+import { alert } from "@/helper/message";
+import { SceneTypeDesc, SceneTypeDomain, SceneTypePaths } from "@/constant/scene";
 
 const props = defineProps<{
   caseId: number;
@@ -72,10 +76,18 @@ const menus = computed(() => {
         );
       },
     },
+    {
+      key: "syncScene",
+      label: "带看",
+      onClick: async () => {
+        const href = await getSWKKSyncLink(caseId);
+        window.open(href);
+      },
+    },
     ...(props.lastMenu || []).map((item) => ({
       ...item,
       onClick: () => item.onClick(caseId),
     })),
   ];
 });
-</script>
+</script>

+ 77 - 4
src/view/case/help.ts

@@ -1,10 +1,14 @@
 import { appConstant } from "@/app";
-import { SceneTypeDomain, SceneTypePaths } from "@/constant/scene";
+import {
+  SceneTypeDesc,
+  SceneTypeDomain,
+  SceneTypePaths,
+} from "@/constant/scene";
 import { alert } from "@/helper/message";
-import { getCaseSceneList } from "@/store/case";
+import { getCaseSceneList, getSyncSceneInfo } from "@/store/case";
 import { CaseTagging } from "@/store/caseTagging";
-import { SceneType } from "@/store/scene";
-import { user } from "@/store/user";
+import { ModelScene, QuoteScene, Scene, SceneType } from "@/store/scene";
+import { transformSWToken, user } from "@/store/user";
 import { base64ToBlob, drawImage } from "@/util";
 
 export type MenuItem = {
@@ -32,6 +36,48 @@ export const getFuseCodeLink = (caseId: number, query?: boolean) => {
   return url.href;
 };
 
+export const getSWKKSyncLink = async (caseId: number) => {
+  const scenes = await getCaseSceneList(caseId);
+  const supportTypes = [SceneType.SWKK, SceneType.SWKJ];
+  const kkScenes = scenes.filter((scene) =>
+    supportTypes.includes(scene.type)
+  ) as QuoteScene[];
+
+  let msg: string | null = null;
+  if (!scenes.length) {
+    msg = "当前案件下无场景,请先添加场景。";
+  } else if (!kkScenes.length) {
+    msg = `带看仅支持${supportTypes
+      .map((type) => SceneTypeDesc[type])
+      .join("、")}类型场景,请添加此类型场景。`;
+  }
+  if (msg) {
+    alert(msg);
+    throw msg;
+  }
+
+  const url = new URL(
+    SceneTypePaths[SceneType.SWKK][2],
+    SceneTypeDomain[SceneType.SWKK]
+  );
+  console.log(SceneTypePaths[SceneType.SWKK]);
+  const roomId = await getSyncSceneInfo(caseId);
+  const params = {
+    vruserId: user.value.info.userName,
+    platform: "fd",
+    roomId,
+    role: "leader",
+    avatar: user.value.info.avatar,
+    name: user.value.info.userName,
+    isTour: "0",
+    m: kkScenes[0].num,
+  };
+  for (const [name, val] of Object.entries(params)) {
+    url.searchParams.append(name, val || "");
+  }
+  return url;
+};
+
 export const checkScenesOpen = async (caseId: number, url: URL | string) => {
   const scenes = await getCaseSceneList(caseId);
   if (!scenes.length) {
@@ -183,3 +229,30 @@ export const fuseImageJoinHot = async (
 
   return blob;
 };
+
+export enum OpenType {
+  query,
+  edit,
+}
+export const openSceneUrl = async (scene: Scene, type: OpenType) => {
+  const pathname = SceneTypePaths[scene.type][type];
+  const url = new URL(pathname || "", window.location.href);
+  if (scene.type === SceneType.SWMX) {
+    url.searchParams.append(
+      "modelId",
+      (scene as ModelScene).modelId.toString()
+    );
+    url.hash = "#sign-model";
+    url.searchParams.append("share", "1");
+  } else {
+    url.searchParams.append("m", (scene as QuoteScene).num);
+
+    if (type === OpenType.edit) {
+      url.searchParams.append(
+        "token",
+        await transformSWToken(scene as QuoteScene)
+      );
+    }
+  }
+  window.open(url);
+};

+ 17 - 1
src/view/case/sceneList.vue

@@ -12,6 +12,21 @@
     </el-table-column>
     <el-table-column label="拍摄/创建时间" prop="createTime"></el-table-column>
     <el-table-column label="操作" v-slot:default="{ row }: { row: Scene }">
+      <span
+        class="oper-span"
+        v-pddept="[row, 'view']"
+        @click="openSceneUrl(row, OpenType.query)"
+      >
+        查看
+      </span>
+      <span
+        v-if="row.type !== SceneType.SWMX"
+        class="oper-span"
+        v-pddept="[row, 'edit']"
+        @click="openSceneUrl(row, OpenType.edit)"
+      >
+        编辑
+      </span>
       <span class="oper-span delBtn" v-pdscene="row" @click="delCaseScene(row)">
         删除
       </span>
@@ -26,6 +41,7 @@ import { confirm } from "@/helper/message";
 import { getCaseSceneList, getCaseScenes, replaceCaseScenes } from "@/store/case";
 import { Scene, SceneType } from "@/store/scene";
 import { onMounted, ref } from "vue";
+import { openSceneUrl, OpenType } from "./help";
 
 const props = defineProps<{
   caseId: number;
@@ -51,4 +67,4 @@ const delCaseScene = async (scene: Scene) => {
   }
 };
 onMounted(refresh);
-</script>
+</script>

+ 1 - 1
src/view/layout/top/index.vue

@@ -60,4 +60,4 @@ const updatePwdHandler = async () => {
 
 <style lang="scss" scoped>
 @import "./style.scss";
-</style>
+</style>

+ 17 - 6
src/view/organization/edit.vue

@@ -25,8 +25,8 @@
         :modelValue="superiorValue"
         @update:modelValue="(val: string[]) => updateSuperiorValue(val)"
         :options="organTrees"
-        :props="{ checkStrictly: true, label: 'name', value: 'id' }"
-      ></el-cascader>
+        :props="{ checkStrictly: true, label: 'name', value: 'id', disabled: 'disabled' }"
+      />
     </el-form-item>
     <el-form-item label="负责人">
       <el-input v-model="bindDept.leader" maxlength="30" placeholder="请输入"></el-input>
@@ -94,7 +94,7 @@ const updateSuperiorValue = (value: string[]) => {
 defineExpose<QuiskExpose>({
   async submit() {
     const { name, deptType, parentId, phone } = bindDept.value;
-    if (!name) {
+    if (!name.trim()) {
       ElMessage.error("组织名称不能为空!");
       throw "组织名称不能为空!";
     } else if (!deptType) {
@@ -104,8 +104,8 @@ defineExpose<QuiskExpose>({
       ElMessage.error("上级组织不能为空!");
       throw "上级组织不能为空!";
     } else if (phone && !PHONE.REG.test(phone)) {
-      ElMessage.error("联系电话格式不正确");
-      throw "联系电话格式不正确";
+      ElMessage.error("请输入11位正确手机号。");
+      throw "请输入11位正确手机号。";
     }
 
     await (bindDept.value.id
@@ -115,6 +115,17 @@ defineExpose<QuiskExpose>({
 });
 
 onMounted(async () => {
-  organTrees.value = await getOrganizationTree("1");
+  const trees = await getOrganizationTree("1");
+  const changeStatus = (trees: Organization[], fDisabled: boolean = false) =>
+    trees.map((item) => {
+      const disabled = fDisabled || item.id === bindDept.value.id;
+      return {
+        ...item,
+        disabled,
+        children: item.children && changeStatus(item.children, disabled),
+      };
+    });
+
+  organTrees.value = changeStatus(trees);
 });
 </script>

+ 1 - 1
src/view/organization/index.vue

@@ -232,4 +232,4 @@ onMounted(refresh);
 .dispatch-detial .el-form-item__label {
   color: #646566;
 }
-</style>
+</style>

+ 1 - 1
src/view/role/index.vue

@@ -108,4 +108,4 @@ const editHandler = async (role: Role) => {
   await editRole(role.id);
   refresh();
 };
-</script>
+</script>

+ 7 - 1
src/view/system/forget.vue

@@ -34,13 +34,19 @@
       <p class="err-info">{{ verification.psw }}</p>
       <el-input
         v-model="form.psw"
+        :maxlength="16"
         placeholder="请输入8-16位数字、英文大小写组合密码"
         type="password"
       ></el-input>
     </el-form-item>
     <el-form-item class="panel-form-item" label="确认密码">
       <p class="err-info">{{ verification.regPsw }}</p>
-      <el-input v-model="form.regPsw" placeholder="请确认密码" type="password"></el-input>
+      <el-input
+        v-model="form.regPsw"
+        placeholder="请确认密码"
+        type="password"
+        :maxlength="16"
+      ></el-input>
     </el-form-item>
 
     <div class="panel-form-item">

+ 13 - 2
src/view/system/login.vue

@@ -10,6 +10,7 @@
         <el-form-item class="panel-form-item">
           <p class="err-info">{{ verification.phone }}</p>
           <el-input
+            :maxlength="11"
             v-model.trim="form.phone"
             placeholder="手机号"
             @keydown.enter="submitClick"
@@ -19,6 +20,7 @@
           <p class="err-info">{{ verification.psw }}</p>
           <el-input
             v-model="form.psw"
+            :maxlength="16"
             placeholder="密码"
             :type="flag ? 'password' : 'text'"
             @keydown.enter="submitClick"
@@ -68,10 +70,11 @@
 import { reactive, watch, ref, computed } from "vue";
 import { openErrorMsg, baseURL, getCode } from "@/request";
 import { PHONE } from "@/constant/REG";
-import { guid } from "@/util";
+import { guid, strToParams } from "@/util";
 import { RouteName, router } from "@/router";
 import { login } from "@/store/system";
 import { appConstant } from "@/app";
+import { user } from "@/store/user";
 
 // 是否显示明文密码
 const flag = ref(true);
@@ -135,7 +138,15 @@ const submitClick = async () => {
       localStorage.setItem("remember", "0");
     }
 
-    router.replace({ name: RouteName.scene });
+    const params = strToParams(window.location.search);
+    if ("redirect" in params) {
+      const url = new URL(unescape(params.redirect));
+      url.searchParams.delete("token");
+      url.searchParams.append("token", user.value.token);
+      window.location.replace(url);
+    } else {
+      router.replace({ name: RouteName.scene });
+    }
   } catch (e) {
     console.error(e);
     return refer();

+ 12 - 2
src/view/system/register.vue

@@ -21,7 +21,11 @@
     </el-form-item>
     <el-form-item class="panel-form-item" label="手机号">
       <p class="err-info">{{ verification.phone }}</p>
-      <el-input v-model="form.phone" placeholder="请输入手机号码"></el-input>
+      <el-input
+        v-model="form.phone"
+        placeholder="请输入手机号码"
+        :maxlength="11"
+      ></el-input>
     </el-form-item>
     <el-form-item class="panel-form-item" label="验证码">
       <p class="err-info">{{ verification.code }}</p>
@@ -47,13 +51,19 @@
       <p class="err-info">{{ verification.psw }}</p>
       <el-input
         v-model="form.psw"
+        :maxlength="16"
         placeholder="请输入8-16位数字、英文大小写组合密码"
         type="password"
       ></el-input>
     </el-form-item>
     <el-form-item class="panel-form-item" label="确认密码">
       <p class="err-info">{{ verification.regPsw }}</p>
-      <el-input v-model="form.regPsw" placeholder="请确认密码" type="password"></el-input>
+      <el-input
+        v-model="form.regPsw"
+        placeholder="请确认密码"
+        type="password"
+        :maxlength="16"
+      ></el-input>
     </el-form-item>
 
     <div class="panel-form-item">

+ 2 - 1
src/view/user/edit.vue

@@ -42,12 +42,13 @@
         <el-input
           v-model.trim="bindUser.userName"
           placeholder="请输入11位手机号码作为用户账号"
+          :maxlength="11"
         ></el-input>
       </el-form-item>
       <el-form-item label="登录密码" class="mandatory">
         <el-input
           v-model="bindUser.password"
-          maxlength="45"
+          :maxlength="16"
           placeholder="请输入8-16位数字、英文大小写组合密码"
           :type="plainFlag ? 'text' : 'password'"
         >

+ 1 - 1
src/view/user/index.vue

@@ -140,4 +140,4 @@ const switchUserStatus = async (row: UserInfo) => {
 };
 </script>
 
-<style scoped lang="scss"></style>
+<style scoped lang="scss"></style>

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

@@ -37,7 +37,7 @@
       <span
         class="oper-span"
         v-pddept="[row, 'view']"
-        @click="openQuery(row)"
+        @click="openSceneUrl(row, OpenType.query)"
         v-if="row.createStatus === ModelSceneStatus.SUCCESS"
       >
         查看
@@ -77,6 +77,7 @@ import { confirm } from "@/helper/message";
 import { useUpload } from "@/hook/upload";
 import { ScenePagging } from "./pagging";
 import { watchPolling } from "@/hook/watchPolling";
+import { OpenType, openSceneUrl } from "../case/help";
 
 const props = defineProps<{ pagging: ScenePagging }>();
 
@@ -90,15 +91,6 @@ const getStatusText = (scene: ModelScene) => {
   return desc;
 };
 
-const openQuery = (scene: ModelScene) => {
-  const pathname = SceneTypePaths[scene.type][0];
-  const url = new URL(pathname || "", window.location.href);
-  url.searchParams.append("modelId", scene.modelId.toString());
-  url.hash = "#sign-model";
-  url.searchParams.append("share", "1");
-  window.open(url);
-};
-
 const delOrCancel = async (scene: ModelScene) => {
   const isDel = scene.createStatus !== ModelSceneStatus.RUN;
   const msg = isDel ? "确定要删除此数据?" : "确定要取消上传吗?";

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

@@ -6,7 +6,7 @@ export const useScenePagging = () => {
   const pagging = usePagging({
     get: getScenePagging,
     paramsTemlate: {
-      type: SceneType.SWKJ,
+      type: SceneType.SWKK,
       sceneName: "",
       modelTitle: "",
     },

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

@@ -15,7 +15,7 @@
         {{ pagging.state.pag.size * (pagging.state.pag.currentPage - 1) + $index + 1 }}
       </div>
     </el-table-column>
-    <el-table-column label="场景标题" prop="sceneName"></el-table-column>
+    <el-table-column label="场景标题" 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 }">
@@ -59,21 +59,7 @@ import { ScenePagging } from "./pagging";
 import { sceneDownload } from "../window";
 import { QuoteSceneStatusDesc, SceneTypePaths } from "@/constant/scene";
 import { transformSWToken } from "@/store/user";
+import { OpenType, openSceneUrl } from "../case/help";
 
 defineProps<{ pagging: ScenePagging }>();
-
-enum OpenType {
-  query,
-  edit,
-}
-const openSceneUrl = async (scene: QuoteScene, type: OpenType) => {
-  const pathname = SceneTypePaths[scene.type][type];
-  const url = new URL(pathname || "", window.location.href);
-  url.searchParams.append("m", (scene as QuoteScene).num);
-  if (type === OpenType.edit) {
-    url.searchParams.append("token", await transformSWToken(scene));
-  }
-
-  window.open(url);
-};
 </script>

+ 1 - 1
vite.config.ts

@@ -3,7 +3,7 @@ import vue from "@vitejs/plugin-vue";
 import { resolve } from "path";
 import ElementPlus from "unplugin-element-plus/vite";
 
-let app = "fire";
+let app = "criminal";
 if (process.argv.length > 3) {
   app = process.argv[process.argv.length - 1].trim();
 }