Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion frontend/src/features/plans/RouteMap.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,28 @@ it("uses the same compact order number and full hover label on the fallback map"
providerName="amap"
start={{ label: "家", position: { latitude: 22.54, longitude: 114.05 } }}
markers={markers}
route={null}
route={{
task_ids: [7],
distance_meters: 1000,
duration_seconds: 600,
polyline: [
{ latitude: 22.54, longitude: 114.05 },
{ latitude: 22.55, longitude: 114.06 },
],
}}
selectedTaskId={null}
onSelectTask={onSelectTask}
/>,
);

const marker = screen.getByRole("button", { name: "订单 #12,虚构定位客户,路线第 1 站" });
const homeMarker = screen.getByTitle("家(起点与终点)");
const routeLine = screen.getByRole("img", { name: "按真实坐标绘制的路线" }).querySelector("polyline");
expect(marker).toHaveTextContent("#12");
expect(marker).toHaveAttribute("title", "订单 #12 · 虚构定位客户 · 路线第 1 站");
expect(homeMarker).toHaveClass("bg-emerald-600");
expect(homeMarker).not.toHaveClass("bg-slate-900");
expect(routeLine).toHaveAttribute("stroke", "#f97316");
expect(screen.queryByText("虚构定位客户")).not.toBeInTheDocument();
fireEvent.click(marker);
expect(onSelectTask).toHaveBeenCalledWith(7);
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/features/plans/RouteMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { useEffect, useMemo, useRef, useState } from "react";

import {
AmapMapProvider,
HOME_MARKER_COLOR_CLASS,
ROUTE_LINE_COLOR,
hasAmapBrowserKey,
hasAmapBrowserSecurityCode,
markerDisplayOffset,
Expand Down Expand Up @@ -90,11 +92,11 @@ function CoordinateCanvas({
</pattern>
</defs>
<rect width="100" height="100" fill="url(#route-grid)" />
{polyline ? <polyline points={polyline} fill="none" stroke="#0f172a" strokeWidth="1.3" strokeLinejoin="round" strokeLinecap="round" /> : null}
{polyline ? <polyline points={polyline} fill="none" stroke={ROUTE_LINE_COLOR} strokeWidth="1.3" strokeLinejoin="round" strokeLinecap="round" /> : null}
</svg>
{start ? (() => {
const projected = project(start.position);
return <span className="absolute flex -translate-1/2 items-center gap-1 rounded-full border-2 border-white bg-emerald-700 px-2 py-1 text-xs font-bold whitespace-nowrap text-white shadow-md" style={{ left: `${projected.left}%`, top: `${projected.top}%` }} title={`${start.label}(起点与终点)`}>家 · 起终点</span>;
return <span className={`absolute flex -translate-1/2 items-center gap-1 rounded-full border-2 border-emerald-100 px-2 py-1 text-xs font-bold whitespace-nowrap text-white shadow-md ${HOME_MARKER_COLOR_CLASS}`} style={{ left: `${projected.left}%`, top: `${projected.top}%` }} title={`${start.label}(起点与终点)`}>家 · 起终点</span>;
})() : null}
{markers.map((marker, index) => {
const projected = project(marker.position);
Expand Down
33 changes: 33 additions & 0 deletions frontend/src/features/plans/mapProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,39 @@ afterEach(() => {
delete window.AMap;
});

it("uses a warm route line and a green home marker", async () => {
const provider = new AmapMapProvider();
const controller = await provider.mount(document.createElement("div"), {
start: { label: "家", position: { latitude: 22.54, longitude: 114.05 } },
markers: [],
polyline: [
{ latitude: 22.54, longitude: 114.05 },
{ latitude: 22.55, longitude: 114.06 },
],
selectedTaskId: null,
locationEditing: false,
draftPosition: null,
}, {
onSelectTask: vi.fn(),
});

const homeMarker = markerInstances.find((marker) => marker.options.title === "家");
const homeContent = homeMarker?.options.content as HTMLDivElement;
expect(homeContent.className).toContain("bg-emerald-600");
expect(homeContent.className).not.toContain("bg-slate-900");

const routeLine = markerInstances.find((marker) => marker.options.strokeColor);
expect(routeLine?.options).toMatchObject({
strokeColor: "#f97316",
strokeOpacity: 0.9,
isOutline: true,
outlineColor: "#fff7ed",
showDir: false,
});

controller.dispose();
});

it("places a GCJ-02 draft pin on map click and updates it after dragging", async () => {
const onDraftPositionChange = vi.fn();
const provider = new AmapMapProvider();
Expand Down
25 changes: 14 additions & 11 deletions frontend/src/features/plans/mapProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export interface MapRenderModel {
draftPosition?: PlanGeoPoint | null;
}

export const ROUTE_LINE_COLOR = "#f97316";
export const HOME_MARKER_COLOR_CLASS = "bg-emerald-600";

export interface MapInteractionCallbacks {
onSelectTask: (taskId: number) => void;
onDraftPositionChange?: (position: PlanGeoPoint) => void;
Expand Down Expand Up @@ -128,18 +131,15 @@ function position(point: PlanGeoPoint): [number, number] {
return [point.longitude, point.latitude];
}

function markerContent(
function homeMarkerContent(
label: string,
name: string | null = null,
selected = false,
offset: MarkerDisplayOffset = { x: 0, y: 0 },
muted = false,
): HTMLDivElement {
const content = document.createElement("div");
content.className = [
"flex items-center gap-1 rounded-full border-2 border-white px-2 py-1",
"flex items-center gap-1 rounded-full border-2 border-emerald-100 px-2 py-1",
"max-w-36 text-xs font-bold whitespace-nowrap text-white shadow-md",
selected ? "bg-amber-600 ring-2 ring-amber-300" : muted ? "bg-slate-400" : "bg-slate-900",
HOME_MARKER_COLOR_CLASS,
].join(" ");
const sequence = document.createElement("span");
sequence.textContent = label;
Expand All @@ -150,7 +150,6 @@ function markerContent(
customerName.textContent = name;
content.append(customerName);
}
content.style.transform = `translate(${offset.x}px, ${offset.y}px)`;
return content;
}

Expand Down Expand Up @@ -273,7 +272,7 @@ export class AmapMapProvider implements MapProvider {
position: position(model.start.position),
title: model.start.label,
anchor: "center",
content: markerContent("家", "起终点"),
content: homeMarkerContent("家", "起终点"),
}),
);
}
Expand Down Expand Up @@ -302,11 +301,15 @@ export class AmapMapProvider implements MapProvider {
overlays.push(
new AMap.Polyline({
path: model.polyline.map(position),
strokeColor: "#0f172a",
strokeColor: ROUTE_LINE_COLOR,
strokeWeight: 5,
strokeOpacity: 0.82,
strokeOpacity: 0.9,
isOutline: true,
outlineColor: "#fff7ed",
borderWeight: 2,
lineJoin: "round",
showDir: true,
lineCap: "round",
showDir: false,
}),
);
}
Expand Down