123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- <template>
- <div v-if="data" class="graphic-header">
- <div class="title">
- <ui-icon class="head-icon" type="return" @click="router.back" />
- <p>{{ isRoad ? "现场绘图" : "事故照片" }}</p>
- </div>
- <div class="actions">
- <div
- v-for="menu in menus"
- :key="menu.text"
- :class="{ disabled: menu.disable }"
- class="action fun-ctrl"
- @click="menu.onClick"
- >
- <ui-icon :type="menu.icon" />
- <p>{{ menu.text }}</p>
- <ui-input
- v-if="menu.icon === 'map'"
- :modelValue="graphicState.showBackImage"
- class="map-status"
- type="checkbox"
- />
- </div>
- </div>
- <div class="table">
- <ui-input
- v-if="options"
- v-model="(data as AccidentPhoto).type"
- :options="options"
- height="32px"
- type="select"
- width="120px"
- />
- <ui-button
- :class="{ ['save-file']: isRoad }"
- :type="isRoad ? undefined : 'primary'"
- class="save"
- width="100px"
- @click="saveHandler"
- >
- {{ isRoad ? "保存" : "完成" }}
- </ui-button>
- <ui-button
- v-if="isRoad"
- class="save"
- type="primary"
- width="100px"
- @click="createTable"
- >
- 制表
- </ui-button>
- </div>
- <div
- class="meterPerPixel"
- v-if="currentMeterPerPixel && isRoad"
- :style="{ color: graphicState.showBackImage ? '#fff' : '#16181A' }"
- >
- 1 : {{ currentMeterPerPixel }}
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import UiIcon from "@/components/base/components/icon/index.vue";
- import UiButton from "@/components/base/components/button/index.vue";
- import { Mode } from "./menus";
- import { changeStore, drawRef, graphicState } from "@/hook/useGraphic";
- import { computed, onActivated, onDeactivated, ref, watchEffect } from "vue";
- import { router, writeRouteName } from "@/router";
- import { AccidentPhoto, accidentPhotos, types } from "@/store/accidentPhotos";
- import { useData } from "./data";
- import UiInput from "@/components/base/components/input/index.vue";
- import { roadPhotos } from "@/store/roadPhotos";
- import { uploadImage } from "@/store/sync";
- import { genUseLoading } from "@/hook";
- import { dataService } from "@/graphic/Service/DataService";
- const data = useData();
- const mode = computed(() => Number(router.currentRoute.value.params.mode) as Mode);
- const isRoad = computed(() => mode.value === Mode.Road);
- const options = computed(() =>
- !isRoad.value ? types.map((t) => ({ label: t, value: t })) : null
- );
- const currentMeterPerPixel = ref();
- let interval;
- onActivated(() => {
- interval = setInterval(() => {
- if (drawRef.value) {
- const coordinate = drawRef.value.coordinate;
- const p1 = coordinate.getXYFromScreen({ x: 0, y: 0 });
- const p2 = coordinate.getXYFromScreen({ x: 0, y: 1 });
- const num = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
- const meterPerPixel = (num * coordinate.res * 100) / coordinate.ratio / 100;
- currentMeterPerPixel.value = Math.round(1 / meterPerPixel);
- }
- }, 200);
- });
- onDeactivated(() => clearInterval(interval));
- const backImageChang = (show) => {
- dataService.setGridDisplay(!show);
- drawRef.value.uiControl.menu_backgroundImg(show);
- };
- watchEffect(() => {
- if (data.value && drawRef.value) {
- backImageChang(true);
- }
- });
- type Menu = { disable?: boolean; text: string; icon: string; onClick: () => void };
- const menus = computed<Menu[]>(() => {
- const menus = [
- {
- text: "",
- icon: "backout",
- disable: !graphicState.value.canRevoke,
- onClick: () => {
- drawRef.value.uiControl.menu_revoke();
- changeStore();
- },
- },
- {
- text: "",
- icon: "redo",
- disable: !graphicState.value.canRecovery,
- onClick: () => {
- drawRef.value.uiControl.menu_recovery();
- changeStore();
- },
- },
- {
- text: "",
- icon: "clear",
- onClick: () => {
- drawRef.value.uiControl.menu_clear();
- changeStore();
- },
- },
- {
- icon: "reset",
- text: "",
- onClick: () => drawRef.value.uiControl.menu_view_reset(),
- },
- ];
- if (isRoad.value) {
- menus.splice(menus.length - 1, 0, {
- icon: "map",
- text: ``,
- onClick: () => backImageChang(!graphicState.value.showBackImage),
- });
- }
- return menus;
- });
- const saveStore = genUseLoading(async () => {
- const newData = {
- ...data.value,
- data: JSON.parse(JSON.stringify(drawRef.value.load.save())),
- };
- const blob = await drawRef.value.uiControl.screenShot();
- newData.url = await uploadImage(blob);
- const origin = isRoad.value ? roadPhotos.value : accidentPhotos.value;
- const index = origin.indexOf(data.value);
- if (~index) {
- origin[index] = newData;
- } else {
- origin.push(newData);
- }
- });
- const saveHandler = async () => {
- await saveStore();
- if (!isRoad.value) {
- await router.replace({
- name: isRoad.value ? writeRouteName.roads : writeRouteName.accidents,
- });
- } else {
- router.replace({
- name: writeRouteName.graphic,
- params: { mode: Mode.Road, id: data.value.id, action: "update" },
- });
- }
- };
- const createTable = async () => {
- await saveStore();
- await router.replace({
- name: writeRouteName.tabulation,
- params: { id: data.value.id },
- });
- };
- </script>
- <style lang="scss" scoped>
- .graphic-header {
- display: flex;
- position: relative;
- width: 100%;
- height: 100%;
- align-items: center;
- justify-content: center;
- }
- .actions {
- display: flex;
- }
- .action {
- font-size: 20px;
- margin: 0 15px;
- display: flex;
- flex-direction: column;
- align-items: center;
- position: relative;
- justify-content: center;
- p {
- font-size: 14px;
- text-align: center;
- }
- }
- .table,
- .title {
- position: absolute;
- top: 50%;
- transform: translateY(-50%);
- }
- .title {
- left: 0;
- display: flex;
- align-items: center;
- p {
- margin-left: 10px;
- }
- }
- .table {
- right: 0;
- }
- .save {
- margin-left: 16px;
- }
- .map-status {
- pointer-events: none;
- position: absolute;
- left: 100%;
- transform: translateX(-50%);
- bottom: 0;
- z-index: 1;
- }
- .head-icon {
- width: 32px;
- height: 32px;
- background: rgba(255, 255, 255, 0.1);
- border-radius: 24px 24px 24px 24px;
- font-size: 16px !important;
- display: flex;
- justify-content: center;
- align-items: center;
- margin-left: -3px;
- }
- .meterPerPixel {
- position: absolute;
- top: 100%;
- right: 24px;
- margin-top: 24px;
- pointer-events: none;
- font-size: 20px;
- font-weight: 400;
- line-height: 23px;
- }
- </style>
- <style lang="scss">
- .map-status.ui-input,
- .map-status.ui-input .checkbox {
- width: 12px;
- height: 7px;
- }
- .map-status.ui-input .checkbox input + .replace {
- border-radius: 4px;
- background-color: #7e7e7e;
- position: absolute;
- border: none;
- &:before {
- content: "";
- display: block;
- position: absolute;
- height: 5px;
- border-radius: 50%;
- width: 5px;
- background-color: #fff;
- top: 1px;
- left: 1px;
- transition: all 0.3s ease;
- }
- i {
- display: none;
- }
- &.checked {
- background-color: var(--colors-primary-base) !important;
- &:before {
- left: calc(100% - 6px);
- }
- }
- }
- .save-file.save {
- border-color: #3a3d3d;
- background-color: #3a3d3d !important;
- color: #fff;
- }
- </style>
|