123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- <template>
- <div class="layout" v-if="roadPhoto">
- <ui-button @click="downLayoutImage">下载</ui-button>
- <ui-button @click="history.undo" type="primary" :class="{disabled: !history.state.hasUndo}">撤销</ui-button>
- <ui-button @click="history.redo" type="primary" :class="{disabled: !history.state.hasRedo}">恢复</ui-button>
- <ui-button type="primary" @click="roadPhoto.table = history.value">保存</ui-button>
- <div class="content" ref="layoutRef">
- <h2>{{ roadPhoto.title || "默认名称" }}</h2>
- <table>
- <tr>
- <td class="label" width="150">到达事故现场时间</td>
- <td class="value">
- <ui-input
- type="text"
- @input="input"
- v-model="history.value.arrivalTime"
- @blur="history.push"
- />
- </td>
- <td class="label" width="100">天气</td>
- <td class="value" width="80">
- <ui-input
- type="text"
- @input="input"
- v-model="history.value.weather"
- @blur="history.push"
- />
- </td>
- <td class="label" width="100">路面性质</td>
- <td class="value" width="150">
- <ui-input
- type="text"
- @input="input"
- v-model="history.value.conditions"
- @blur="history.push"
- />
- </td>
- </tr>
- <tr>
- <td class="label">事故发生地点</td>
- <td class="value" colspan="5">
- <ui-input
- type="text"
- @input="input"
- v-model="history.value.location"
- @blur="history.push"
- />
- </td>
- </tr>
- <tr>
- <td class="image" colspan="6">
- <div>
- <img :src="getStaticFile(roadPhoto.photoUrl)" @blur="history.push" class="photo" />
- <img
- src="/static/compass.png"
- :style="{transform: `rotateZ(${history.value.compassAngle}deg)`}"
- class="compass"
- @mousedown="downHandler"
- />
- </div>
- </td>
- </tr>
- <tr>
- <td class="value" colspan="6">
- <ui-input
- type="text"
- @input="input"
- v-model="history.value.illustrate"
- @blur="history.push"
- />
- </td>
- </tr>
- <tr>
- <td class="value" colspan="6">
- <ui-input
- type="text"
- @input="input"
- v-model="history.value.other"
- @blur="history.push"
- />
- </td>
- </tr>
- </table>
- <div class="signatures">
- <p class="signature">绘图员:</p>
- <p class="signature">当事人签名:</p>
- <p class="signature">勘察员:</p>
- <p class="signature">见证人签名:</p>
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { router, writeRouteName } from '@/router'
- import {computed, ref} from "vue";
- import { useHistory } from '@/hook/useHistory'
- import {roadPhotos, RoadPhoto, getDefaultTable} from "@/store/roadPhotos";
- import {getStaticFile} from "@/dbo/main";
- import html2canvas from 'html2canvas'
- import UiButton from "@/components/base/components/button/index.vue";
- import UiInput from "@/components/base/components/input/index.vue";
- import { mathUtil } from '@/graphic/Util/MathUtil'
- import {getPostionByTarget} from "@/components/base/utils";
- const roadPhoto = computed<RoadPhoto>(() => {
- const route = router.currentRoute.value;
- const params = route.params
- let data
- if (route.name !== writeRouteName.tabulation) {
- return null
- } else if (!params.id || !(data = roadPhotos.value.find(data => data.id === params.id))) {
- router.back();
- return null;
- }
- return data
- })
- const history = computed(
- () => roadPhoto.value && useHistory(getDefaultTable(roadPhoto.value))
- )
- const input = () => {
- history.value.state.hasRedo = false
- }
- const downHandler = (ev: MouseEvent) => {
- const target = (ev.target as HTMLImageElement)
- const page = getPostionByTarget(target, document.documentElement)
- const start = { x: page.x + target.offsetWidth / 2, y: page.y }
- const center = { x: page.x + target.offsetWidth / 2, y: page.y + target.offsetHeight / 2 }
- let angle
- const moveHandler = (ev: MouseEvent) => {
- const move = {
- x: ev.pageX,
- y: ev.pageY
- }
- angle = mathUtil.Angle(center, start, move)
- angle = move.x < start.x ? -angle : angle
- target.style.transform = `rotateZ(${angle}deg)`
- ev.stopPropagation();
- ev.preventDefault();
- }
- const upHandler = (ev:MouseEvent) => {
- document.documentElement.removeEventListener("mousemove", moveHandler)
- document.documentElement.removeEventListener("mouseup", upHandler);
- ev.stopPropagation();
- ev.preventDefault();
- history.value.value.compassAngle = angle
- history.value.push()
- }
- document.documentElement.addEventListener("mousemove", moveHandler)
- document.documentElement.addEventListener("mouseup", upHandler)
- ev.stopPropagation();
- ev.preventDefault();
- }
- const layoutRef = ref<HTMLDivElement>()
- const downLayoutImage = async () => {
- const canvas = await html2canvas(layoutRef.value)
- const blob = await new Promise<Blob>(resolve => canvas.toBlob(resolve, "image/jpeg", 0.95))
- window.open(URL.createObjectURL(blob))
- }
- </script>
- <style lang="scss" scoped>
- .layout {
- overflow-y: auto;
- height: 100%;
- }
- .content {
- box-sizing: content-box;
- width: 980px;
- height: 1300px;
- padding: 20px;
- padding-bottom: 60px;
- margin: 0 auto;
- }
- .image {
- position: relative;
- div {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- top: 0;
- .photo {
- max-width: 100%;
- max-height: 100%;
- }
- .compass {
- position: absolute;
- right: 20px;
- top: 20px;
- width: 60px;
- }
- }
- }
- .content table {
- width: 980px;
- height: 800px;
- border: 2px solid #000;
- border-collapse: collapse;
- td:not(:last-child) {
- border-right: 2px solid #000;
- }
- tr:not(:last-child) td {
- border-bottom: 2px solid #000;
- }
- .value {
- height: 43px;
- }
- }
- .signatures {
- display: flex;
- .signature {
- flex: 1;
- }
- }
- </style>
- <style lang="scss">
- .value {
- box-sizing: border-box;
- padding: 8px 10px;
- input,
- .ui-input {
- width: 100%;
- height: 100%;
- padding: 0 !important;
- outline: none !important;
- border: none !important;
- color: #000 !important;
- }
- }
- </style>
|