Major changes: - New frontend (platform/web/): Vite + React 18 + TypeScript + Tailwind - 4-module navigation: 数据送标 / 模型管理 / 车队管理 / 系统管理 - Data catalog with charts (DMS/ADAS/Lane 3-tab view) - Quality review workflow (标注质检): Good/Fine/Bad scoring with auto-advance - Audit enhancements: batch operations, rejection categories, Feishu notifications - Operation audit log (操作日志) - World model simulation studio (仿真工坊) - Dataset version management with snapshots and diff - ADAS 7-class dataset integration (138K images organized + compressed) - User management with Feishu integration and pagination - CRUD/search/filter on all pages, card layout redesign - PIL-optimized image overlay rendering - Auto-snapshot on build, in_review workflow stage - Removed embedded algorithm code (now in workspace)
149 lines
3.4 KiB
JavaScript
149 lines
3.4 KiB
JavaScript
import React from "react";
|
|
import { __RouterContext as RouterContext } from "react-router";
|
|
import { createPath } from 'history';
|
|
import PropTypes from "prop-types";
|
|
import invariant from "tiny-invariant";
|
|
import {
|
|
resolveToLocation,
|
|
normalizeToLocation
|
|
} from "./utils/locationUtils.js";
|
|
|
|
// React 15 compat
|
|
const forwardRefShim = C => C;
|
|
let { forwardRef } = React;
|
|
if (typeof forwardRef === "undefined") {
|
|
forwardRef = forwardRefShim;
|
|
}
|
|
|
|
function isModifiedEvent(event) {
|
|
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
|
|
}
|
|
|
|
const LinkAnchor = forwardRef(
|
|
(
|
|
{
|
|
innerRef, // TODO: deprecate
|
|
navigate,
|
|
onClick,
|
|
...rest
|
|
},
|
|
forwardedRef
|
|
) => {
|
|
const { target } = rest;
|
|
|
|
let props = {
|
|
...rest,
|
|
onClick: event => {
|
|
try {
|
|
if (onClick) onClick(event);
|
|
} catch (ex) {
|
|
event.preventDefault();
|
|
throw ex;
|
|
}
|
|
|
|
if (
|
|
!event.defaultPrevented && // onClick prevented default
|
|
event.button === 0 && // ignore everything but left clicks
|
|
(!target || target === "_self") && // let browser handle "target=_blank" etc.
|
|
!isModifiedEvent(event) // ignore clicks with modifier keys
|
|
) {
|
|
event.preventDefault();
|
|
navigate();
|
|
}
|
|
}
|
|
};
|
|
|
|
// React 15 compat
|
|
if (forwardRefShim !== forwardRef) {
|
|
props.ref = forwardedRef || innerRef;
|
|
} else {
|
|
props.ref = innerRef;
|
|
}
|
|
|
|
/* eslint-disable-next-line jsx-a11y/anchor-has-content */
|
|
return <a {...props} />;
|
|
}
|
|
);
|
|
|
|
if (__DEV__) {
|
|
LinkAnchor.displayName = "LinkAnchor";
|
|
}
|
|
|
|
/**
|
|
* The public API for rendering a history-aware <a>.
|
|
*/
|
|
const Link = forwardRef(
|
|
(
|
|
{
|
|
component = LinkAnchor,
|
|
replace,
|
|
to,
|
|
innerRef, // TODO: deprecate
|
|
...rest
|
|
},
|
|
forwardedRef
|
|
) => {
|
|
return (
|
|
<RouterContext.Consumer>
|
|
{context => {
|
|
invariant(context, "You should not use <Link> outside a <Router>");
|
|
|
|
const { history } = context;
|
|
|
|
const location = normalizeToLocation(
|
|
resolveToLocation(to, context.location),
|
|
context.location
|
|
);
|
|
|
|
const href = location ? history.createHref(location) : "";
|
|
const props = {
|
|
...rest,
|
|
href,
|
|
navigate() {
|
|
const location = resolveToLocation(to, context.location);
|
|
const isDuplicateNavigation = createPath(context.location) === createPath(normalizeToLocation(location));
|
|
const method = (replace || isDuplicateNavigation) ? history.replace : history.push;
|
|
|
|
method(location);
|
|
}
|
|
};
|
|
|
|
// React 15 compat
|
|
if (forwardRefShim !== forwardRef) {
|
|
props.ref = forwardedRef || innerRef;
|
|
} else {
|
|
props.innerRef = innerRef;
|
|
}
|
|
|
|
return React.createElement(component, props);
|
|
}}
|
|
</RouterContext.Consumer>
|
|
);
|
|
}
|
|
);
|
|
|
|
if (__DEV__) {
|
|
const toType = PropTypes.oneOfType([
|
|
PropTypes.string,
|
|
PropTypes.object,
|
|
PropTypes.func
|
|
]);
|
|
const refType = PropTypes.oneOfType([
|
|
PropTypes.string,
|
|
PropTypes.func,
|
|
PropTypes.shape({ current: PropTypes.any })
|
|
]);
|
|
|
|
Link.displayName = "Link";
|
|
|
|
Link.propTypes = {
|
|
innerRef: refType,
|
|
onClick: PropTypes.func,
|
|
replace: PropTypes.bool,
|
|
target: PropTypes.string,
|
|
to: toType.isRequired
|
|
};
|
|
}
|
|
|
|
export default Link;
|