header.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <template>
  2. <div class="graphic-header" v-if="data">
  3. <div class="title">
  4. <ui-icon type="return" @click="back" class="head-icon" />
  5. <p>{{ isRoad ? '现场绘图' : '事故照片' }}</p>
  6. </div>
  7. <div class="actions">
  8. <div
  9. v-for="menu in menus"
  10. :key="menu.text"
  11. class="action fun-ctrl"
  12. :class="{disabled: menu.disable}"
  13. @click="menu.onClick"
  14. >
  15. <ui-icon :type="menu.icon" />
  16. <p>{{ menu.text }}</p>
  17. <ui-input
  18. type="checkbox"
  19. :modelValue="graphicState.showBackImage"
  20. class="map-status"
  21. v-if="menu.icon === 'map'"
  22. />
  23. </div>
  24. </div>
  25. <div class="table">
  26. <ui-input
  27. width="120px"
  28. height="32px"
  29. type="select"
  30. :options="options"
  31. v-model="(data as AccidentPhoto).type"
  32. v-if="options"
  33. />
  34. <ui-button width="100px" class="save save-file" @click="saveHandler">
  35. 保存
  36. </ui-button>
  37. <ui-button width="100px" type="primary" class="save" @click="createTable" v-if="isRoad">
  38. 制表
  39. </ui-button>
  40. </div>
  41. </div>
  42. </template>
  43. <script setup lang="ts">
  44. import UiIcon from "@/components/base/components/icon/index.vue";
  45. import UiButton from "@/components/base/components/button/index.vue";
  46. import {Mode} from './menus'
  47. import {changeStore, drawRef, graphicState} from '@/hook/useGraphic'
  48. import {computed, watchEffect} from "vue";
  49. import {router, writeRouteName} from '@/router'
  50. import {AccidentPhoto, accidentPhotos, types} from '@/store/accidentPhotos'
  51. import {useData} from './data'
  52. import UiInput from "@/components/base/components/input/index.vue";
  53. import {roadPhotos} from "@/store/roadPhotos";
  54. import {back, uploadImage} from '@/store/sync'
  55. import {genUseLoading} from "@/hook";
  56. import {dataService} from "@/graphic/Service/DataService";
  57. const data = useData()
  58. const mode = computed(() => Number(router.currentRoute.value.params.mode) as Mode)
  59. const isRoad = computed(() => mode.value === Mode.Road)
  60. const options = computed(() =>
  61. !isRoad.value ? types.map(t => ({ label: t, value: t })) : null
  62. )
  63. const backImageChang = (show) => {
  64. dataService.setGridDisplay(!show)
  65. drawRef.value.uiControl.menu_backgroundImg(show)
  66. }
  67. watchEffect(() => {
  68. if (data.value && drawRef.value) {
  69. backImageChang(true)
  70. }
  71. })
  72. type Menu = {disable?: boolean, text: string, icon: string, onClick: () => void}
  73. const menus = computed<Menu[]>(() => {
  74. const menus = [
  75. {
  76. text: "",
  77. icon: "backout",
  78. disable: !graphicState.value.canRevoke,
  79. onClick: () => {
  80. drawRef.value.uiControl.menu_revoke()
  81. changeStore()
  82. }
  83. },
  84. {
  85. text: "",
  86. icon: "redo",
  87. disable: !graphicState.value.canRecovery,
  88. onClick: () => {
  89. drawRef.value.uiControl.menu_recovery()
  90. changeStore()
  91. }
  92. },
  93. {
  94. text: "",
  95. icon: "clear",
  96. onClick: () => {
  97. drawRef.value.uiControl.menu_clear()
  98. changeStore()
  99. }
  100. },
  101. {
  102. icon: "reset",
  103. text: "",
  104. onClick: () => drawRef.value.uiControl.menu_view_reset()
  105. }
  106. ]
  107. if (isRoad.value) {
  108. menus.splice(menus.length - 1, 0, {
  109. icon: "map",
  110. text: ``,
  111. onClick: () => backImageChang(!graphicState.value.showBackImage)
  112. })
  113. }
  114. return menus
  115. })
  116. const saveStore = genUseLoading(async () => {
  117. const newData = {
  118. ...data.value,
  119. data: JSON.parse(JSON.stringify(drawRef.value.load.save()))
  120. }
  121. const blob = await drawRef.value.uiControl.screenShot()
  122. newData.url = await uploadImage(blob)
  123. const origin = isRoad.value ? roadPhotos.value : accidentPhotos.value
  124. const index = origin.indexOf(data.value)
  125. if (~index) {
  126. origin[index] = newData
  127. } else {
  128. origin.push(newData)
  129. }
  130. })
  131. const saveHandler = async () => {
  132. await saveStore()
  133. await router.replace({name: isRoad.value ? writeRouteName.roads : writeRouteName.accidents})
  134. }
  135. const createTable = async () => {
  136. await saveStore()
  137. await router.replace({name: writeRouteName.tabulation, params: {id: data.value.id} })
  138. }
  139. </script>
  140. <style scoped lang="scss">
  141. .graphic-header {
  142. display: flex;
  143. position: relative;
  144. width: 100%;
  145. height: 100%;
  146. align-items: center;
  147. justify-content: center;
  148. }
  149. .actions {
  150. display: flex;
  151. }
  152. .action {
  153. font-size: 20px;
  154. margin: 0 15px;
  155. display: flex;
  156. flex-direction: column;
  157. align-items: center;
  158. position: relative;
  159. justify-content: center;
  160. p {
  161. font-size: 14px;
  162. text-align: center;
  163. }
  164. }
  165. .table,
  166. .title {
  167. position: absolute;
  168. top: 50%;
  169. transform: translateY(-50%);
  170. }
  171. .title {
  172. left: 0;
  173. display: flex;
  174. align-items: center;
  175. p {
  176. margin-left: 10px;
  177. }
  178. }
  179. .table {
  180. right: 0;
  181. }
  182. .save {
  183. margin-left: 24px;
  184. }
  185. .map-status {
  186. pointer-events: none;
  187. position: absolute;
  188. left: 100%;
  189. transform: translateX(-50%);
  190. bottom: 0;
  191. z-index: 1;
  192. }
  193. </style>
  194. <style lang="scss">
  195. .map-status.ui-input,
  196. .map-status.ui-input .checkbox{
  197. width: 12px;
  198. height: 7px;
  199. }
  200. .map-status.ui-input .checkbox input + .replace {
  201. border-radius: 4px;
  202. background-color: #7E7E7E;
  203. position: absolute;
  204. border: none;
  205. &:before {
  206. content: "";
  207. display: block;
  208. position: absolute;
  209. height: 5px;
  210. border-radius: 50%;
  211. width: 5px;
  212. background-color: #fff;
  213. top: 1px;
  214. left: 1px;
  215. transition: all .3s ease;
  216. }
  217. i {
  218. display: none;
  219. }
  220. &.checked{
  221. background-color: var(--colors-primary-base) !important;
  222. &:before {
  223. left: calc(100% - 6px);
  224. }
  225. }
  226. }
  227. .save-file.save {
  228. border-color: #3a3d3d;
  229. background-color: #3a3d3d !important;
  230. color: #fff;
  231. }
  232. </style>