cc12458 hace 3 semanas
padre
commit
bdb529851e

+ 30 - 9
src/lib/fabric/brush/class/PolygonBrush.ts

@@ -1,7 +1,7 @@
 import type { Canvas, FabricObjectProps, TBrushEventData, XY } from 'fabric';
 import type { PolygonShape } from '../types';
 
-import { Point, Polygon, Shadow } from 'fabric';
+import { Rect, Point, Polygon, Shadow } from 'fabric';
 import { ShapeBrush } from './ShapeBrush';
 import { mergeObjectOptions } from '@/lib/fabric';
 
@@ -114,6 +114,7 @@ type BrushInvalidReason = 'outOfRegion' | 'selfIntersection' | 'degenerateTriang
 export class PolygonBrush extends ShapeBrush<PolygonShape> {
   /** 有效顶点数达到该值即自动闭合落成;默认 100;三角形工具用 3。 */
   vertexTargetCount = 100;
+  private readonly rect: Rect;
 
   private get vc() {
     return this.shape === 'triangle' ? 3 : this.vertexTargetCount;
@@ -133,15 +134,17 @@ export class PolygonBrush extends ShapeBrush<PolygonShape> {
   areaEps = 13;
 
   private vertices: XY[] = [];
-  private moveHint: XY | null = null;
+  private moveHint: Point | null = null;
 
   constructor(canvas: Canvas) {
     super(canvas);
-  }
-
-  onMouseDoubleClick(pointer: Point, { e }: TBrushEventData): void {
-    if (!this.canvas._isMainEvent(e)) return;
-    this.tryCloseFromKeyboardOrDblClick({ x: pointer.x, y: pointer.y });
+    this.rect = new Rect({
+      width: this.decimate / 2,
+      height: this.decimate / 2,
+      fill: this.color,
+      selectable: false,
+      evented: false,
+    })
   }
 
   private closeSnapSq(): number {
@@ -200,6 +203,7 @@ export class PolygonBrush extends ShapeBrush<PolygonShape> {
     poly.setCoords();
     this._resetShadow();
     this.canvas.fire('object:created', { object: poly });
+    this.canvas.remove(this.rect);
     return true;
   }
 
@@ -220,6 +224,11 @@ export class PolygonBrush extends ShapeBrush<PolygonShape> {
     return ok;
   }
 
+  onMouseDoubleClick(pointer: Point, { e }: TBrushEventData): void {
+    if (!this.canvas._isMainEvent(e)) return;
+    this.tryCloseFromKeyboardOrDblClick({ x: pointer.x, y: pointer.y });
+  }
+
   onMouseDown(pointer: Point, { e }: TBrushEventData): void {
     if (!this.canvas._isMainEvent(e)) return;
     if (this._isOutSideContainer(pointer)) return;
@@ -254,6 +263,7 @@ export class PolygonBrush extends ShapeBrush<PolygonShape> {
     }
 
     this.vertices.push(r);
+    if (this.vertices.length === 1) this._renderVertex(r);
 
     if (this.vertices.length === this.vertexTargetCount) {
       if (this.isTriangleTool()) {
@@ -279,8 +289,12 @@ export class PolygonBrush extends ShapeBrush<PolygonShape> {
     this.refreshPreview();
   }
 
-  onMouseUp({ e }: TBrushEventData): boolean {
-    if (!this.canvas._isMainEvent(e)) return false;
+  onMouseUp(event: TBrushEventData): boolean {
+    if (this.moveHint) {
+      this.onMouseDown(this.moveHint, event)
+      this.moveHint = null;
+    }
+    if (!this.canvas._isMainEvent(event.e)) return false;
     if (this.isTriangleTool() && this.vertices.length >= 3) return false;
     if (this.isPolygonTool()) return this.vertices.length > 0;
     return this.vertices.length > 0 && this.vertices.length < 3;
@@ -309,10 +323,17 @@ export class PolygonBrush extends ShapeBrush<PolygonShape> {
   reset(): void {
     this.vertices = [];
     this.moveHint = null;
+    this.canvas.remove(this.rect);
     this.canvas.clearContext(this.canvas.contextTop);
     this.canvas.requestRenderAll();
   }
 
+  private _renderVertex(point: Point) {
+    this.rect.setXY(point);
+    this.rect.fill = this.color;
+    this.canvas.add(this.rect);
+  }
+
   protected override cleanupBrushState(): void {
     this.vertices = [];
     this.moveHint = null;

+ 4 - 1
src/modules/monitor/Annotator/Annotator.vue

@@ -76,7 +76,10 @@ async function complete() {
 async function picker(object: AnnotatorObject) {
   if (!object) return false;
   const result = await startAnnotator(object, props.picker);
-  if (typeof result === 'string') object.annotatorId = result;
+  if (typeof result === 'string') {
+    if (object.annotatorId === result) return;
+    object.annotatorId = result;
+  }
   const canvas = toValue(fabric.canvas);
   if (canvas) {
     canvas.remove(object);

+ 3 - 2
src/modules/monitor/composables/useAnnotatorFlow.ts

@@ -84,9 +84,10 @@ export function useAnnotatorFlow(data: Ref<MedicalModel>, options: UseAnnotatorF
       try {
         const values = await options.picker<string[]>({ title: `标注${picture.label}`, withDefault: false, props: { scope: key, seed } });
         seed = values[0];
+        object.strokeWidth = 2;
         object.stroke = hashStringToColor(seed);
       } catch {}
-      return seed;
+      return seed ?? false;
     };
     const result = await options.opener<AnnotatorExportObject>({
       type: 'annotator',
@@ -200,7 +201,7 @@ export function useAnnotatorFlow(data: Ref<MedicalModel>, options: UseAnnotatorF
         .join('<br>');
 
       row.columns[1] = value || (sub ? row.columns[2] : '');
-      row.exception = annotator.size > 1 || !row.columns[1].includes(row.columns[2]);
+      row.exception = annotator.size > 1 || !row.columns[1].split('<br>').includes(row.columns[2]);
     }
   }
 

+ 7 - 13
src/platform/file.ts

@@ -38,23 +38,17 @@ function filenameFromUrl(url: string): string {
  */
 export function downloadFromUrl(url: string, options?: DownloadFromUrlOptions): Promise<void> {
   return (async () => {
-    const res = await fetch(url, options?.fetchInit);
-    if (!res.ok) throw new Error(`下载失败: ${res.status} ${res.statusText}`);
-
-    const blob = await res.blob();
-    const filename = options?.filename ?? filenameFromContentDisposition(res.headers.get('content-disposition')) ?? filenameFromUrl(url);
-
-    const objectUrl = URL.createObjectURL(blob);
+    const filename = options?.filename ?? filenameFromUrl(url);
     try {
       const a = document.createElement('a');
-      a.href = objectUrl;
+      a.href = url;
       a.download = filename;
       a.rel = 'noopener';
       document.body.appendChild(a);
       a.click();
       a.remove();
     } finally {
-      URL.revokeObjectURL(objectUrl);
+
     }
   })();
 }
@@ -68,16 +62,16 @@ export async function printFromUrl(url: string, options?: { rollback?: boolean;
       } catch {
         window.AIO?.print?.(url);
       }
-    } catch (e) {
+    } catch (e: any) {
       Notify.warning(`打印失败 (${e.message})`, { duration: 1500 });
       closed = true;
     }
   } else {
     try {
       const current = window.open(url, '_blank');
-      closed = current.closed;
-      current.location.href;
-    } catch (e) {
+      closed = current?.closed ?? true;
+      if (current) current.location.href;
+    } catch (e: any) {
       Notify.warning(`无法打开窗口 (${e.message})`, { duration: 1500 });
       closed = true;
     }

+ 2 - 2
src/request/model/medical-report.model.ts

@@ -1,7 +1,7 @@
 import type { MedicalReportData, MedicalReportModel } from '@/request/model/medical-record.model';
 import type { AnnotatorTreeNode } from '@/request/model/annotator.model';
-import type { AnnotatorExportObject, AnnotatorObject } from '@/lib/Annotator';
-import type { CropperExportObject } from '@/lib/Cropper';
+import type { AnnotatorExportObject, AnnotatorObject } from '@/modules/monitor/Annotator';
+import type { CropperExportObject } from '@/modules/monitor/Cropper';
 import type { AnalysisData, AnalysisModel } from '@/request/model/analysis.model';
 
 import dayjs from 'dayjs';

+ 1 - 1
src/request/model/scheme.model.ts

@@ -84,6 +84,6 @@ function fromSchemeGoods(data?: Data): SchemeGoodsProps | void {
     label: data?.buyName ?? '去购买',
     value: data?.buyUrl,
   } satisfies SchemeGoodsProps;
-  if (result.type === 'miniprogram') { result.value = data.miniprogram; }
+  if (result.type === 'miniprogram') { result.value = data?.miniprogram; }
   return result.value ? result : void 0;
 }