Compare commits
85 Commits
fetch-test
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| aba4a8aeb6 | |||
| 87dbc7548a | |||
| 6cddddb601 | |||
| 4f5dd15cd1 | |||
| 0391599a04 | |||
| cfe87a78cb | |||
| 9778a0f26a | |||
| 260917dfb4 | |||
| b1be380334 | |||
| 83dd5356e0 | |||
| a2fed17b48 | |||
| f6b253e6ef | |||
| bb517741b9 | |||
| caae0492ee | |||
| 131a88fd22 | |||
| 5b93b6ff7d | |||
| 8855901f5c | |||
| 8df62e2388 | |||
| c34f4c8503 | |||
| 588f55552d | |||
| 5a57fa5ede | |||
| 008fc12db9 | |||
| 191d218ec4 | |||
| 956494b3ed | |||
| 9f1cf21042 | |||
| 279bbe8536 | |||
| 1fb128ede5 | |||
| c10b507cf6 | |||
| d751fc10a7 | |||
| c386350df5 | |||
| e92be97393 | |||
| 8974ea802a | |||
| 1058767515 | |||
| fffd37a0a9 | |||
| aec67101cb | |||
| e73b4e73ad | |||
| f1c3c23127 | |||
| 394e6d8342 | |||
| c690d50baa | |||
| 0305bd64a7 | |||
| 45c2309662 | |||
| 9898a5ea38 | |||
| 73c41b76ab | |||
| 9791e76d17 | |||
| fdeb455e47 | |||
| c942a2ce07 | |||
| 624fc38b21 | |||
| 3459cae699 | |||
| cb46f91846 | |||
| e99567e6b3 | |||
| a1b3335664 | |||
| 0df19c9cfb | |||
| ad600ce059 | |||
| 46ff61eaed | |||
| 2fa64e66c9 | |||
| 8b7e86b8bf | |||
| 5d5a24ac89 | |||
| 77bf48f88a | |||
| 2aa93f941e | |||
| 304edcbb38 | |||
| 71bc00cc4e | |||
| 3239f819d0 | |||
| e14f03cf79 | |||
| 9340252c25 | |||
| df8e6bf515 | |||
| 5d34bc3643 | |||
| 2f0196ae4a | |||
| 94f83d36ff | |||
| e3829d2fcc | |||
| 58f5ca7f22 | |||
| 7a0096caed | |||
| 3fc8f883cf | |||
| 0b6ae9fc5c | |||
| b907cc4299 | |||
| 26213aaa76 | |||
| 2c3227fb64 | |||
| 3286d4366a | |||
| 4aae686264 | |||
| 88c8bbb2a7 | |||
| 59a9743992 | |||
| 42a4a9f566 | |||
| 5055e40de6 | |||
| c0ea1fb9f3 | |||
| 2b39c1dd1a | |||
| 1f1d94ed84 |
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# <!-- Powered by BMAD™ Core -->
|
# <!-- Powered by BMAD™ Core -->
|
||||||
template:
|
template:
|
||||||
id: competitor-analysis-template-v2
|
id: competitor-analysis-template-v2
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -147,3 +147,4 @@ Thumbs.db
|
|||||||
tmp/
|
tmp/
|
||||||
temp/
|
temp/
|
||||||
nul
|
nul
|
||||||
|
/nextjs-frontend
|
||||||
19
AGENTS.md
Normal file
19
AGENTS.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## Project Structure & Module Organization
|
||||||
|
The primary Vite application lives in `src/`, with feature folders such as `components/ai`, `components/auth`, and `components/dashboard` grouping screens, while shared primitives stay in `components/ui` alongside the `cn` helper. Domain utilities and integrations sit in `lib/`, typed contracts in `types/`, and global styles in `styles/`. Reference notes, migration guides, and UX briefs belong in `docs/`. Build artifacts are staged in `build/` and `bundles/` - regenerate them instead of editing in place. The `crop-x/` workspace hosts the API-driven Next.js toolchain, and `nextjs-frontend/` contains a Jest-enabled prototype; treat each as an isolated package with its own dependencies.
|
||||||
|
|
||||||
|
## Build, Test, and Development Commands
|
||||||
|
Install dependencies with `npm install` at the repository root before any work. Launch the Vite dev server via `npm run dev` and build production bundles with `npm run build`. When touching the Next.js workspace, switch into `crop-x/` (or `nextjs-frontend/`) and run the same `npm run dev` / `npm run build` loop; lint with `npm run lint` and regenerate OpenAPI clients through `npm run generate-client`. The Next.js prototype keeps Jest wired - execute `npm test` or `npm run coverage` from `nextjs-frontend/` to validate UI contracts.
|
||||||
|
|
||||||
|
## Coding Style & Naming Conventions
|
||||||
|
Author components as TypeScript function components, export them with PascalCase names, and keep props camelCase. Align layout and spacing with Tailwind classes; reach for `components/ui` primitives before adding bespoke markup. Follow the established single-quote, semicolon-terminated formatting visible in `src/App.tsx`. In the Next.js packages, run Prettier (`npm run prettier`) when formatting cross-file changes and keep ESLint green before opening a review.
|
||||||
|
|
||||||
|
## Testing Guidelines
|
||||||
|
Automated coverage is concentrated in `nextjs-frontend/__tests__` using Jest and Testing Library; mirror existing file naming (`*.test.tsx`) when adding scenarios. For the Vite app, smoke the key dashboards after significant UI changes: authentication, machinery, fields, operations, assets, AI models, and irrigation. Document manual steps or screenshots in the PR when you touch flows without automated tests.
|
||||||
|
|
||||||
|
## Commit & Pull Request Guidelines
|
||||||
|
Commit messages currently follow the "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵͳ - <summary>" prefix; keep that Chinese tag and supply a short, imperative summary. Group related changes per commit so reviewers can bisect easily. Pull requests should describe the user-visible impact, list any config or schema updates, and attach before/after captures for UI adjustments. Link tracking tickets where possible and flag required environment variables (`VITE_API_BASE_URL`, etc.) if they change.
|
||||||
|
|
||||||
|
## Security & Configuration Tips
|
||||||
|
Never commit secrets - use `.env.local` entries for API hosts and credentials, and document new keys in `docs/` instead. When adding third-party scripts, load them through vetted helpers like `lib/mapLoader` to keep CSP compliance intact. Review generated OpenAPI clients before shipping to ensure endpoints line up with the deployed backend.
|
||||||
47
Dockerfile.crop-x-new
Normal file
47
Dockerfile.crop-x-new
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
FROM registry.dev.maimaiag.com/library/node:20-alpine AS base
|
||||||
|
RUN npm config set registry https://registry.npmmirror.com/
|
||||||
|
|
||||||
|
# Install dependencies only when needed
|
||||||
|
FROM base AS deps
|
||||||
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
|
RUN apk add --no-cache libc6-compat
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies based on the preferred package manager
|
||||||
|
COPY crop-x-new/package.json crop-x-new/package-lock.json ./
|
||||||
|
RUN npm ci --registry=https://registry.npmmirror.com/
|
||||||
|
|
||||||
|
|
||||||
|
# Rebuild the source code only when needed
|
||||||
|
FROM base AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY crop-x-new/ .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production image, copy all the files and run next
|
||||||
|
FROM base AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
|
# COPY --from=builder /app/public ./public
|
||||||
|
|
||||||
|
# Automatically leverage output traces to reduce image size
|
||||||
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENV PORT=3000
|
||||||
|
|
||||||
|
ENV HOSTNAME="0.0.0.0"
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
41
crop-x-new/.gitignore
vendored
Normal file
41
crop-x-new/.gitignore
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
/.pnp
|
||||||
|
.pnp.*
|
||||||
|
.yarn/*
|
||||||
|
!.yarn/patches
|
||||||
|
!.yarn/plugins
|
||||||
|
!.yarn/releases
|
||||||
|
!.yarn/versions
|
||||||
|
|
||||||
|
# testing
|
||||||
|
/coverage
|
||||||
|
|
||||||
|
# next.js
|
||||||
|
/.next/
|
||||||
|
/out/
|
||||||
|
|
||||||
|
# production
|
||||||
|
/build
|
||||||
|
|
||||||
|
# misc
|
||||||
|
.DS_Store
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# debug
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# env files (can opt-in for committing if needed)
|
||||||
|
.env*
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
47
crop-x-new/Dockerfile
Normal file
47
crop-x-new/Dockerfile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
FROM registry.dev.maimaiag.com/library/node:20-alpine AS base
|
||||||
|
RUN npm config set registry https://registry.npmmirror.com/
|
||||||
|
|
||||||
|
# Install dependencies only when needed
|
||||||
|
FROM base AS deps
|
||||||
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
|
RUN apk add --no-cache libc6-compat
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies based on the preferred package manager
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --registry=https://registry.npmmirror.com/
|
||||||
|
|
||||||
|
|
||||||
|
# Rebuild the source code only when needed
|
||||||
|
FROM base AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production image, copy all the files and run next
|
||||||
|
FROM base AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
|
||||||
|
# Automatically leverage output traces to reduce image size
|
||||||
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENV PORT=3000
|
||||||
|
|
||||||
|
ENV HOSTNAME="0.0.0.0"
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
36
crop-x-new/README.md
Normal file
36
crop-x-new/README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
First, run the development server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
# or
|
||||||
|
yarn dev
|
||||||
|
# or
|
||||||
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
|
|
||||||
|
## Learn More
|
||||||
|
|
||||||
|
To learn more about Next.js, take a look at the following resources:
|
||||||
|
|
||||||
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
|
|
||||||
|
## Deploy on Vercel
|
||||||
|
|
||||||
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
22
crop-x-new/components.json
Normal file
22
crop-x-new/components.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "default",
|
||||||
|
"rsc": false,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "tailwind.config.js",
|
||||||
|
"css": "src/styles/globals.css",
|
||||||
|
"baseColor": "neutral",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
|
"iconLibrary": "lucide",
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"utils": "@/lib/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib",
|
||||||
|
"hooks": "@/hooks"
|
||||||
|
},
|
||||||
|
"registries": {}
|
||||||
|
}
|
||||||
4
crop-x-new/docs/eslint-fix.md
Normal file
4
crop-x-new/docs/eslint-fix.md
Normal file
File diff suppressed because one or more lines are too long
2012
crop-x-new/docs/开发项目规范.md
Normal file
2012
crop-x-new/docs/开发项目规范.md
Normal file
File diff suppressed because it is too large
Load Diff
18
crop-x-new/eslint.config.mjs
Normal file
18
crop-x-new/eslint.config.mjs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
|
import nextVitals from "eslint-config-next/core-web-vitals";
|
||||||
|
import nextTs from "eslint-config-next/typescript";
|
||||||
|
|
||||||
|
const eslintConfig = defineConfig([
|
||||||
|
...nextVitals,
|
||||||
|
...nextTs,
|
||||||
|
// Override default ignores of eslint-config-next.
|
||||||
|
globalIgnores([
|
||||||
|
// Default ignores of eslint-config-next:
|
||||||
|
".next/**",
|
||||||
|
"out/**",
|
||||||
|
"build/**",
|
||||||
|
"next-env.d.ts",
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
export default eslintConfig;
|
||||||
11
crop-x-new/global.d.ts
vendored
Normal file
11
crop-x-new/global.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export {};
|
||||||
|
declare global {
|
||||||
|
type CamelCase<S extends string> =
|
||||||
|
S extends `${infer P}_${infer R}`
|
||||||
|
? `${P}${Capitalize<CamelCase<R>>}`
|
||||||
|
: S;
|
||||||
|
|
||||||
|
type CamelKeys<T> = {
|
||||||
|
[K in keyof T as CamelCase<K & string>]: T[K];
|
||||||
|
};
|
||||||
|
}
|
||||||
6
crop-x-new/lib/utils.ts
Normal file
6
crop-x-new/lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { clsx, type ClassValue } from "clsx"
|
||||||
|
import { twMerge } from "tailwind-merge"
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
6
crop-x-new/next-env.d.ts
vendored
Normal file
6
crop-x-new/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
import "./.next/types/routes.d.ts";
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
36
crop-x-new/next.config.ts
Normal file
36
crop-x-new/next.config.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// next.config.ts
|
||||||
|
import type { NextConfig } from 'next';
|
||||||
|
|
||||||
|
const nextConfig: NextConfig = {
|
||||||
|
// 构建时报 TS 校验(可按需开启/关闭)
|
||||||
|
typescript: {
|
||||||
|
ignoreBuildErrors: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 将 ESM 包转译(如有 Tree-shaking/TS 产物需要)
|
||||||
|
transpilePackages: ['lucide-react'],
|
||||||
|
|
||||||
|
// 便于部署到容器/Serverless
|
||||||
|
output: 'standalone',
|
||||||
|
|
||||||
|
// 若有其它实验性开关可放这里(保持空对象即可)
|
||||||
|
experimental: {
|
||||||
|
// 例如:typedRoutes: true
|
||||||
|
},
|
||||||
|
|
||||||
|
// 解决工作区根目录问题(通常保持默认即可;你这里明确指定也可)
|
||||||
|
outputFileTracingRoot: process.cwd(),
|
||||||
|
|
||||||
|
// 反向代理(避免本地 CORS)
|
||||||
|
async rewrites() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/api/:path*',
|
||||||
|
destination:
|
||||||
|
'https://gitea-admin-hm-smart-agri-app.dev.maimaiag.com/api/:path*',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
17
crop-x-new/openapi-ts.config.ts
Normal file
17
crop-x-new/openapi-ts.config.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { defineConfig } from "@hey-api/openapi-ts";
|
||||||
|
|
||||||
|
// 获取环境变量配置
|
||||||
|
const baseUrl = process.env.API_BASE_URL || 'http://localhost:8080';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
client: "@hey-api/client-fetch",
|
||||||
|
input: `${baseUrl}/openapi.json`,
|
||||||
|
output: "./src/lib/api",
|
||||||
|
schemas: {
|
||||||
|
name: "types.gen.ts",
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
name: "sdk.gen.ts",
|
||||||
|
},
|
||||||
|
clientName: "client.gen.ts",
|
||||||
|
});
|
||||||
14111
crop-x-new/package-lock.json
generated
Normal file
14111
crop-x-new/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
74
crop-x-new/package.json
Normal file
74
crop-x-new/package.json
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"name": "crop-x-next",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start",
|
||||||
|
"lint": "eslint",
|
||||||
|
"deploy": "node scripts/deploy.js",
|
||||||
|
"api:generate": "node scripts/generate-api.cjs"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@hey-api/openapi-ts": "^0.87.1",
|
||||||
|
"@radix-ui/react-accordion": "^1.2.12",
|
||||||
|
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||||
|
"@radix-ui/react-aspect-ratio": "^1.1.8",
|
||||||
|
"@radix-ui/react-avatar": "^1.1.11",
|
||||||
|
"@radix-ui/react-checkbox": "^1.3.3",
|
||||||
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
|
"@radix-ui/react-context-menu": "^2.2.16",
|
||||||
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
|
"@radix-ui/react-hover-card": "^1.1.15",
|
||||||
|
"@radix-ui/react-label": "^2.1.8",
|
||||||
|
"@radix-ui/react-menubar": "^1.1.16",
|
||||||
|
"@radix-ui/react-navigation-menu": "^1.2.14",
|
||||||
|
"@radix-ui/react-popover": "^1.1.15",
|
||||||
|
"@radix-ui/react-progress": "^1.1.8",
|
||||||
|
"@radix-ui/react-radio-group": "^1.3.8",
|
||||||
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
|
"@radix-ui/react-separator": "^1.1.8",
|
||||||
|
"@radix-ui/react-slider": "^1.3.6",
|
||||||
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
|
"@radix-ui/react-switch": "^1.2.6",
|
||||||
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
|
"@radix-ui/react-toast": "^1.2.15",
|
||||||
|
"@radix-ui/react-toggle": "^1.1.10",
|
||||||
|
"@radix-ui/react-toggle-group": "^1.1.11",
|
||||||
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
|
"axios": "^1.13.2",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"date-fns": "^4.1.0",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
|
"lucide-react": "^0.553.0",
|
||||||
|
"next": "16.0.1",
|
||||||
|
"next-themes": "^0.4.6",
|
||||||
|
"npx": "^10.2.2",
|
||||||
|
"openapi-fetch": "^0.15.0",
|
||||||
|
"react": "19.2.0",
|
||||||
|
"react-day-picker": "^9.11.1",
|
||||||
|
"react-dom": "19.2.0",
|
||||||
|
"react-hook-form": "^7.66.0",
|
||||||
|
"recharts": "^3.4.1",
|
||||||
|
"sonner": "^2.0.7",
|
||||||
|
"tailwind-merge": "^3.4.0",
|
||||||
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"zustand": "^5.0.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4",
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^19",
|
||||||
|
"@types/react-dom": "^19",
|
||||||
|
"eslint": "^9",
|
||||||
|
"eslint-config-next": "16.0.1",
|
||||||
|
"eslint-plugin-unused-imports": "^4.3.0",
|
||||||
|
"tailwindcss": "^4",
|
||||||
|
"tw-animate-css": "^1.4.0",
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
crop-x-new/postcss.config.mjs
Normal file
7
crop-x-new/postcss.config.mjs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
const config = {
|
||||||
|
plugins: {
|
||||||
|
"@tailwindcss/postcss": {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
1
crop-x-new/public/file.svg
Normal file
1
crop-x-new/public/file.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||||
|
After Width: | Height: | Size: 391 B |
1
crop-x-new/public/globe.svg
Normal file
1
crop-x-new/public/globe.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
1
crop-x-new/public/next.svg
Normal file
1
crop-x-new/public/next.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
1
crop-x-new/public/vercel.svg
Normal file
1
crop-x-new/public/vercel.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 128 B |
1
crop-x-new/public/window.svg
Normal file
1
crop-x-new/public/window.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||||
|
After Width: | Height: | Size: 385 B |
387
crop-x-new/scripts/build.cjs
Normal file
387
crop-x-new/scripts/build.cjs
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
/**
|
||||||
|
* 统一构建脚本
|
||||||
|
*
|
||||||
|
* 整合环境设置、API生成和Next.js构建的完整构建流程
|
||||||
|
* 支持多环境构建:dev, test, uat, prod
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { execSync, spawn } = require('child_process');
|
||||||
|
|
||||||
|
// ANSI 颜色代码
|
||||||
|
const colors = {
|
||||||
|
reset: '\x1b[0m',
|
||||||
|
red: '\x1b[31m',
|
||||||
|
green: '\x1b[32m',
|
||||||
|
yellow: '\x1b[33m',
|
||||||
|
blue: '\x1b[34m',
|
||||||
|
cyan: '\x1b[36m',
|
||||||
|
white: '\x1b[37m'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 日志函数
|
||||||
|
function log(message, color = 'white') {
|
||||||
|
console.log(`${colors[color]}${message}${colors.reset}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logSuccess(message) {
|
||||||
|
log(`✓ ${message}`, 'green');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logError(message) {
|
||||||
|
log(`✗ ${message}`, 'red');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logInfo(message) {
|
||||||
|
log(`ℹ ${message}`, 'blue');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logStep(message) {
|
||||||
|
log(`🔄 ${message}`, 'cyan');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logWarning(message) {
|
||||||
|
log(`⚠ ${message}`, 'yellow');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取命令行参数中的环境
|
||||||
|
*/
|
||||||
|
function getEnvironmentFromArgs() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
|
||||||
|
// 查找 --env 参数
|
||||||
|
const envArg = args.find(arg => arg.startsWith('--env='));
|
||||||
|
if (envArg) {
|
||||||
|
return envArg.split('=')[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找直接的参数
|
||||||
|
const directEnv = args[0];
|
||||||
|
if (['dev', 'test', 'uat', 'prod'].includes(directEnv)) {
|
||||||
|
return directEnv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证环境名称
|
||||||
|
*/
|
||||||
|
function validateEnvironment(env) {
|
||||||
|
const validEnvs = ['dev', 'test', 'uat', 'prod'];
|
||||||
|
if (!validEnvs.includes(env)) {
|
||||||
|
logError(`无效的环境名称: ${env}`);
|
||||||
|
logInfo(`支持的环境: ${validEnvs.join(', ')}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制环境配置文件
|
||||||
|
*/
|
||||||
|
function copyEnvironmentConfig(env) {
|
||||||
|
logStep(`设置 ${env} 环境配置`);
|
||||||
|
|
||||||
|
const envDir = path.join(process.cwd(), 'env');
|
||||||
|
const sourceFile = path.join(envDir, `.env.${env}`);
|
||||||
|
const targetFile = path.join(process.cwd(), '.env.local');
|
||||||
|
|
||||||
|
// 检查源文件是否存在
|
||||||
|
if (!fs.existsSync(sourceFile)) {
|
||||||
|
logError(`环境配置文件不存在: ${sourceFile}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 复制文件
|
||||||
|
fs.copyFileSync(sourceFile, targetFile);
|
||||||
|
logSuccess(`已复制环境配置: ${env}`);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logError(`复制环境配置文件失败: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理缓存目录
|
||||||
|
*/
|
||||||
|
function cleanCache() {
|
||||||
|
logStep('清理缓存目录');
|
||||||
|
|
||||||
|
const dirsToClean = ['.next', 'node_modules/.cache'];
|
||||||
|
|
||||||
|
dirsToClean.forEach(dir => {
|
||||||
|
const dirPath = path.join(process.cwd(), dir);
|
||||||
|
if (fs.existsSync(dirPath)) {
|
||||||
|
try {
|
||||||
|
fs.rmSync(dirPath, { recursive: true, force: true });
|
||||||
|
logSuccess(`已清理: ${dir}`);
|
||||||
|
} catch (error) {
|
||||||
|
logWarning(`清理 ${dir} 失败: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成API客户端代码
|
||||||
|
*/
|
||||||
|
function generateApi(env) {
|
||||||
|
logStep('生成API客户端代码');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 设置环境变量
|
||||||
|
const apiBaseUrl = getApiBaseUrl(env);
|
||||||
|
process.env.API_BASE_URL = apiBaseUrl;
|
||||||
|
|
||||||
|
logInfo(`API服务器: ${apiBaseUrl}`);
|
||||||
|
|
||||||
|
// 执行API生成脚本
|
||||||
|
execSync('node scripts/generate-api.cjs', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: process.cwd()
|
||||||
|
});
|
||||||
|
|
||||||
|
logSuccess('API客户端代码生成完成');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logError(`API生成失败: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从环境配置文件中读取配置
|
||||||
|
*/
|
||||||
|
function getEnvConfigFromFile(env) {
|
||||||
|
try {
|
||||||
|
// 读取对应环境配置文件
|
||||||
|
const envFilePath = path.join(process.cwd(), 'env', `.env.${env}`);
|
||||||
|
|
||||||
|
if (!fs.existsSync(envFilePath)) {
|
||||||
|
logWarning(`环境配置文件不存在: ${envFilePath}`);
|
||||||
|
return {
|
||||||
|
FRONTEND_BASE_URL: 'http://localhost:3000',
|
||||||
|
BACKEND_BASE_URL: 'http://localhost:8080',
|
||||||
|
ENV_DESCRIPTION: `${env}环境`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const envContent = fs.readFileSync(envFilePath, 'utf8');
|
||||||
|
const lines = envContent.split('\n');
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
FRONTEND_BASE_URL: 'http://localhost:3000',
|
||||||
|
BACKEND_BASE_URL: 'http://localhost:8080',
|
||||||
|
ENV_DESCRIPTION: `${env}环境`
|
||||||
|
};
|
||||||
|
|
||||||
|
// 解析配置文件
|
||||||
|
for (const line of lines) {
|
||||||
|
if (line.startsWith('FRONTEND_BASE_URL=')) {
|
||||||
|
config.FRONTEND_BASE_URL = line.split('=')[1].trim();
|
||||||
|
} else if (line.startsWith('BACKEND_BASE_URL=')) {
|
||||||
|
config.BACKEND_BASE_URL = line.split('=')[1].trim();
|
||||||
|
logInfo(`从 ${envFilePath} 读取到后端地址: ${config.BACKEND_BASE_URL}`);
|
||||||
|
} else if (line.startsWith('ENV_DESCRIPTION=')) {
|
||||||
|
config.ENV_DESCRIPTION = line.split('=')[1].trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
} catch (error) {
|
||||||
|
logError(`读取环境配置失败: ${error.message}`);
|
||||||
|
return {
|
||||||
|
FRONTEND_BASE_URL: 'http://localhost:3000',
|
||||||
|
BACKEND_BASE_URL: 'http://localhost:8080',
|
||||||
|
ENV_DESCRIPTION: `${env}环境`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取API基础URL - 从环境配置文件中读取
|
||||||
|
*/
|
||||||
|
function getApiBaseUrl(env) {
|
||||||
|
const config = getEnvConfigFromFile(env);
|
||||||
|
return config.BACKEND_BASE_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取前端基础URL - 从环境配置文件中读取
|
||||||
|
*/
|
||||||
|
function getFrontendUrl(env) {
|
||||||
|
const config = getEnvConfigFromFile(env);
|
||||||
|
return config.FRONTEND_BASE_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next.js 构建
|
||||||
|
*/
|
||||||
|
function buildNext(env) {
|
||||||
|
logStep('执行 Next.js 构建');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 设置环境变量
|
||||||
|
process.env.NODE_ENV = 'production'; // 所有构建都使用 production 模式
|
||||||
|
process.env.NEXT_PUBLIC_ENV = env;
|
||||||
|
|
||||||
|
// 执行构建
|
||||||
|
execSync('npm run build', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
cwd: process.cwd()
|
||||||
|
});
|
||||||
|
|
||||||
|
logSuccess('Next.js 构建完成');
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logError(`Next.js 构建失败: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示构建信息
|
||||||
|
*/
|
||||||
|
function showBuildInfo(env, totalTime) {
|
||||||
|
const envConfig = getEnvConfigFromFile(env);
|
||||||
|
|
||||||
|
log('='.repeat(60), 'green');
|
||||||
|
logSuccess(`构建完成!总耗时: ${totalTime}ms`);
|
||||||
|
logSuccess(`环境: ${envConfig.ENV_DESCRIPTION} (${env})`);
|
||||||
|
logSuccess(`前端地址: ${envConfig.FRONTEND_BASE_URL}`);
|
||||||
|
logSuccess(`后端地址: ${envConfig.BACKEND_BASE_URL}`);
|
||||||
|
logSuccess('构建产物: .next 目录');
|
||||||
|
log('='.repeat(60), 'green');
|
||||||
|
|
||||||
|
logInfo('部署建议:');
|
||||||
|
logInfo(` 将 .next 目录和 package.json 部署到 ${envConfig.ENV_DESCRIPTION}`);
|
||||||
|
if (env !== 'dev') {
|
||||||
|
logInfo(` 确保环境变量 NODE_ENV=production 和 NEXT_PUBLIC_ENV=${env}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示帮助信息
|
||||||
|
*/
|
||||||
|
function showHelp() {
|
||||||
|
log('用法: node scripts/build.cjs [环境] [选项]', 'cyan');
|
||||||
|
log('');
|
||||||
|
log('环境:', 'yellow');
|
||||||
|
log(' dev 开发环境', 'white');
|
||||||
|
log(' test 测试环境', 'white');
|
||||||
|
log(' uat UAT 环境', 'white');
|
||||||
|
log(' prod 生产环境', 'white');
|
||||||
|
log('');
|
||||||
|
log('选项:', 'yellow');
|
||||||
|
log(' --env=<environment> 指定环境 (与直接指定环境等效)', 'white');
|
||||||
|
log(' --clean 构建前清理缓存', 'white');
|
||||||
|
log(' --skip-api 跳过API生成', 'white');
|
||||||
|
log(' --skip-build 跳过Next.js构建(仅设置环境)', 'white');
|
||||||
|
log(' --help 显示此帮助信息', 'white');
|
||||||
|
log('');
|
||||||
|
log('示例:', 'yellow');
|
||||||
|
log(' node scripts/build.cjs dev # 开发环境完整构建', 'white');
|
||||||
|
log(' node scripts/build.cjs test --clean # 测试环境清理缓存后构建', 'white');
|
||||||
|
log(' node scripts/build.cjs prod --skip-api # 生产环境跳过API生成构建', 'white');
|
||||||
|
log(' node scripts/build.cjs uat --skip-build # UAT环境仅设置环境和API生成', 'white');
|
||||||
|
log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主函数
|
||||||
|
*/
|
||||||
|
function main() {
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
log('='.repeat(60), 'cyan');
|
||||||
|
log('统一构建脚本', 'cyan');
|
||||||
|
log('整合环境设置、API生成和Next.js构建', 'cyan');
|
||||||
|
log('='.repeat(60), 'cyan');
|
||||||
|
|
||||||
|
// 检查帮助参数
|
||||||
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
||||||
|
showHelp();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取环境参数
|
||||||
|
let env = getEnvironmentFromArgs();
|
||||||
|
if (!env) {
|
||||||
|
logError('请指定环境参数');
|
||||||
|
logInfo('使用 --help 查看帮助信息');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证环境
|
||||||
|
if (!validateEnvironment(env)) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析选项
|
||||||
|
const shouldClean = process.argv.includes('--clean');
|
||||||
|
const skipApi = process.argv.includes('--skip-api');
|
||||||
|
const skipBuild = process.argv.includes('--skip-build');
|
||||||
|
|
||||||
|
logInfo(`目标环境: ${env}`);
|
||||||
|
logInfo(`工作目录: ${process.cwd()}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 设置环境配置
|
||||||
|
const envSuccess = copyEnvironmentConfig(env);
|
||||||
|
if (!envSuccess) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 清理缓存(可选)
|
||||||
|
if (shouldClean) {
|
||||||
|
cleanCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 生成API客户端(可选)
|
||||||
|
if (!skipApi) {
|
||||||
|
const apiSuccess = generateApi(env);
|
||||||
|
if (!apiSuccess) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logInfo('跳过API生成');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Next.js 构建(可选)
|
||||||
|
if (!skipBuild) {
|
||||||
|
const buildSuccess = buildNext(env);
|
||||||
|
if (!buildSuccess) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logInfo('跳过Next.js构建');
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalTime = Date.now() - startTime;
|
||||||
|
showBuildInfo(env, totalTime);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
const totalTime = Date.now() - startTime;
|
||||||
|
logError(`构建失败 (${totalTime}ms): ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行主函数
|
||||||
|
if (require.main === module) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
copyEnvironmentConfig,
|
||||||
|
generateApi,
|
||||||
|
buildNext,
|
||||||
|
validateEnvironment,
|
||||||
|
getEnvironmentFromArgs
|
||||||
|
};
|
||||||
44
crop-x-new/scripts/deploy.js
Normal file
44
crop-x-new/scripts/deploy.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
var data = JSON.stringify({
|
||||||
|
"namespace": "argo",
|
||||||
|
"template_name": "repo-runtime-workflow",
|
||||||
|
"parameters": {
|
||||||
|
"git-schema": "http",
|
||||||
|
"git-domain": "gitea-service-http.cropflow-dev.svc.cluster.local:3000",
|
||||||
|
"git-user": "cavin",
|
||||||
|
"git-repo": "smart-crop-ui",
|
||||||
|
"git-revision": "main",
|
||||||
|
"git-pat": "b6c02bf1aec73d7bbbfbe590ea37564a29c4bd5d",
|
||||||
|
"docker-image-domain": "172.16.102.3:30648",
|
||||||
|
"docker-dockerfile-path": "./Dockerfile.crop-x-new",
|
||||||
|
"resource-cpu-limit": "500m",
|
||||||
|
"resource-memory-limit": "512Mi",
|
||||||
|
"resource-gpu-mem-limit": "",
|
||||||
|
"resource-mount-path": "/data",
|
||||||
|
"resource-mount-capacity": "",
|
||||||
|
"app-namespace": "argo",
|
||||||
|
"app-env-vars": "",
|
||||||
|
"app-ingress-host": ".dev.maimaiag.com",
|
||||||
|
"app-container-port": "3000",
|
||||||
|
"security-scan-enabled": "false"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
method: 'post',
|
||||||
|
url: 'https://gitea-admin-argo-workflow-api-app.dev.maimaiag.com/api/v1/workflows/from-template',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
data : data
|
||||||
|
};
|
||||||
|
|
||||||
|
axios(config)
|
||||||
|
.then(function (response) {
|
||||||
|
|
||||||
|
let url = `https://gitea-admin-argo-workflow-api-app.dev.maimaiag.com/api/v1/workflows/${response.data.name}/log`
|
||||||
|
console.log(`打开 ${url} 查看日志`);
|
||||||
|
})
|
||||||
|
.catch(function (error) {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
356
crop-x-new/scripts/generate-api.cjs
Normal file
356
crop-x-new/scripts/generate-api.cjs
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
/**
|
||||||
|
* 简化的 API 生成脚本
|
||||||
|
*
|
||||||
|
* 这个脚本现在主要负责:
|
||||||
|
* 1. 使用 @hey-api/openapi-ts 命令生成客户端代码
|
||||||
|
* 2. 环境配置通过 openapi-ts.config.ts 处理
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 加载环境变量
|
||||||
|
require('dotenv').config({ path: '.env.local' });
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// 从环境配置文件中读取 API_BASE_URL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ANSI 颜色代码
|
||||||
|
const colors = {
|
||||||
|
reset: '\x1b[0m',
|
||||||
|
red: '\x1b[31m',
|
||||||
|
green: '\x1b[32m',
|
||||||
|
yellow: '\x1b[33m',
|
||||||
|
blue: '\x1b[34m',
|
||||||
|
magenta: '\x1b[35m',
|
||||||
|
cyan: '\x1b[36m',
|
||||||
|
white: '\x1b[37m'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 日志函数
|
||||||
|
function log(message, color = 'white') {
|
||||||
|
console.log(`${colors[color]}${message}${colors.reset}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function logSuccess(message) {
|
||||||
|
log(`✓ ${message}`, 'green');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logError(message) {
|
||||||
|
log(`✗ ${message}`, 'red');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logWarning(message) {
|
||||||
|
log(`⚠ ${message}`, 'yellow');
|
||||||
|
}
|
||||||
|
|
||||||
|
function logInfo(message) {
|
||||||
|
log(`ℹ ${message}`, 'blue');
|
||||||
|
}
|
||||||
|
const API_BASE_URL = process.env.API_BASE_URL
|
||||||
|
// 显示环境配置信息
|
||||||
|
logInfo(`当前环境: ${process.env.NODE_ENV || 'development'}`);
|
||||||
|
logInfo(`API 服务器: ${API_BASE_URL}`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查自定义文件是否存在
|
||||||
|
* 如果某些文件已经被自定义,我们不希望覆盖它们
|
||||||
|
*/
|
||||||
|
function checkCustomFiles() {
|
||||||
|
const customFiles = [
|
||||||
|
'client.gen.ts' // 客户端文件通常是自定义的
|
||||||
|
];
|
||||||
|
|
||||||
|
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||||
|
const existingCustomFiles = [];
|
||||||
|
|
||||||
|
for (const file of customFiles) {
|
||||||
|
const filePath = path.join(outputDir, file);
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
|
// 检查文件是否包含自定义内容的标识
|
||||||
|
const content = fs.readFileSync(filePath, 'utf8');
|
||||||
|
|
||||||
|
// 检查是否有自定义配置的标识
|
||||||
|
const customIndicators = [
|
||||||
|
'getBaseUrl',
|
||||||
|
'createDynamicClient',
|
||||||
|
'getCurrentClientConfig',
|
||||||
|
// 可以添加更多自定义标识
|
||||||
|
];
|
||||||
|
|
||||||
|
const hasCustomContent = customIndicators.some(indicator =>
|
||||||
|
content.includes(indicator)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasCustomContent) {
|
||||||
|
existingCustomFiles.push(file);
|
||||||
|
logWarning(`检测到自定义文件: ${file}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingCustomFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备份自定义文件
|
||||||
|
*/
|
||||||
|
function backupCustomFiles(customFiles) {
|
||||||
|
if (customFiles.length === 0) return;
|
||||||
|
|
||||||
|
logInfo('备份自定义文件...');
|
||||||
|
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||||
|
const backupDir = path.join(process.cwd(), 'src', 'lib', 'api', 'backup');
|
||||||
|
|
||||||
|
// 创建备份目录
|
||||||
|
if (!fs.existsSync(backupDir)) {
|
||||||
|
fs.mkdirSync(backupDir, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
|
const timestampedBackupDir = path.join(backupDir, `backup-${timestamp}`);
|
||||||
|
fs.mkdirSync(timestampedBackupDir);
|
||||||
|
|
||||||
|
for (const file of customFiles) {
|
||||||
|
const srcPath = path.join(outputDir, file);
|
||||||
|
const destPath = path.join(timestampedBackupDir, file);
|
||||||
|
fs.copyFileSync(srcPath, destPath);
|
||||||
|
logInfo(` 备份: ${file} -> backup/${timestamp}/${file}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
logSuccess(`自定义文件已备份到: backup/${timestamp}/`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 恢复自定义文件
|
||||||
|
*/
|
||||||
|
function restoreCustomFiles(customFiles) {
|
||||||
|
if (customFiles.length === 0) return;
|
||||||
|
|
||||||
|
logInfo('恢复自定义文件...');
|
||||||
|
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||||
|
const backupDir = path.join(process.cwd(), 'src', 'lib', 'api', 'backup');
|
||||||
|
|
||||||
|
// 找到最新的备份目录
|
||||||
|
const backupDirs = fs.existsSync(backupDir)
|
||||||
|
? fs.readdirSync(backupDir)
|
||||||
|
.filter(name => name.startsWith('backup-'))
|
||||||
|
.sort()
|
||||||
|
.reverse()
|
||||||
|
: [];
|
||||||
|
|
||||||
|
if (backupDirs.length === 0) {
|
||||||
|
logWarning('没有找到备份文件,跳过恢复');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestBackupDir = path.join(backupDir, backupDirs[0]);
|
||||||
|
|
||||||
|
for (const file of customFiles) {
|
||||||
|
const srcPath = path.join(latestBackupDir, file);
|
||||||
|
const destPath = path.join(outputDir, file);
|
||||||
|
|
||||||
|
if (fs.existsSync(srcPath)) {
|
||||||
|
fs.copyFileSync(srcPath, destPath);
|
||||||
|
logInfo(` 恢复: ${file}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logSuccess('自定义文件已恢复');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载并保存 openapi.json 文件到本地
|
||||||
|
*/
|
||||||
|
function downloadOpenApiJson() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const https = require('https');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const fileUrl = `${API_BASE_URL}/openapi.json`;
|
||||||
|
const outputPath = path.join(process.cwd(), 'scripts', 'openapi.json');
|
||||||
|
|
||||||
|
logInfo(`下载 OpenAPI 规范文件: ${fileUrl}`);
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
// 创建 HTTPS 代理(如果需要,可以忽略 SSL 证书验证)
|
||||||
|
const agent = new https.Agent({
|
||||||
|
rejectUnauthorized: false // 跳过 SSL 证书验证
|
||||||
|
});
|
||||||
|
|
||||||
|
https.get(fileUrl, { agent }, (response) => {
|
||||||
|
if (response.statusCode !== 200) {
|
||||||
|
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = '';
|
||||||
|
|
||||||
|
response.on('data', (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
response.on('end', () => {
|
||||||
|
try {
|
||||||
|
// 验证 JSON 格式
|
||||||
|
JSON.parse(data);
|
||||||
|
|
||||||
|
// 写入文件
|
||||||
|
fs.writeFileSync(outputPath, data, 'utf8');
|
||||||
|
const executionTime = Date.now() - startTime;
|
||||||
|
logSuccess(`OpenAPI 规范已保存到: scripts/openapi.json (${executionTime}ms)`);
|
||||||
|
resolve();
|
||||||
|
} catch (error) {
|
||||||
|
reject(new Error(`JSON 格式错误: ${error.message}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).on('error', (error) => {
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用 openapi-ts 命令生成客户端代码
|
||||||
|
*/
|
||||||
|
function generateWithOpenApiTS() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
logInfo('使用 @hey-api/openapi-ts 生成客户端代码...');
|
||||||
|
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
const command = 'npx @hey-api/openapi-ts';
|
||||||
|
|
||||||
|
logInfo(`执行命令: ${command}`);
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
exec(command, { cwd: process.cwd() }, (error, stdout, stderr) => {
|
||||||
|
const executionTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
logError(`openapi-ts 执行失败 (${executionTime}ms)`);
|
||||||
|
logError(`错误信息: ${error.message}`);
|
||||||
|
if (stderr) {
|
||||||
|
logError(`stderr: ${stderr}`);
|
||||||
|
}
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stderr) {
|
||||||
|
logWarning(`stderr: ${stderr}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
logSuccess(`openapi-ts 执行成功 (${executionTime}ms)`);
|
||||||
|
if (stdout) {
|
||||||
|
logInfo(`输出: ${stdout}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证生成的文件
|
||||||
|
*/
|
||||||
|
function validateGeneratedFiles() {
|
||||||
|
try {
|
||||||
|
logInfo('验证生成的文件...');
|
||||||
|
const outputDir = path.join(process.cwd(), 'src', 'lib', 'api');
|
||||||
|
|
||||||
|
if (!fs.existsSync(outputDir)) {
|
||||||
|
throw new Error('输出目录不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = fs.readdirSync(outputDir);
|
||||||
|
logInfo(`输出目录包含 ${files.length} 个文件:`);
|
||||||
|
|
||||||
|
const requiredFiles = ['types.gen.ts', 'sdk.gen.ts', 'index.ts'];
|
||||||
|
const generatedFiles = [];
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = path.join(outputDir, file);
|
||||||
|
const stats = fs.statSync(filePath);
|
||||||
|
|
||||||
|
// 只显示文件,不显示目录
|
||||||
|
if (stats.isFile()) {
|
||||||
|
const size = (stats.size / 1024).toFixed(2);
|
||||||
|
logInfo(` 📄 ${file} (${size} KB)`);
|
||||||
|
generatedFiles.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查必要文件
|
||||||
|
const missingFiles = requiredFiles.filter(file => !generatedFiles.includes(file));
|
||||||
|
if (missingFiles.length > 0) {
|
||||||
|
logWarning(`缺少期望的文件: ${missingFiles.join(', ')}`);
|
||||||
|
} else {
|
||||||
|
logSuccess('所有期望的文件都已生成');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
logError(`验证生成的文件失败: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主函数
|
||||||
|
*/
|
||||||
|
async function main() {
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
log('='.repeat(60), 'cyan');
|
||||||
|
log('API 客户端代码生成脚本', 'cyan');
|
||||||
|
log('基于 @hey-api/openapi-ts', 'cyan');
|
||||||
|
log('='.repeat(60), 'cyan');
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查是否有自定义文件
|
||||||
|
const customFiles = checkCustomFiles();
|
||||||
|
|
||||||
|
if (customFiles.length > 0) {
|
||||||
|
logInfo('检测到自定义文件,将在生成前进行备份');
|
||||||
|
backupCustomFiles(customFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载 openapi.json 文件到本地
|
||||||
|
await downloadOpenApiJson();
|
||||||
|
|
||||||
|
// 使用 openapi-ts 生成代码
|
||||||
|
await generateWithOpenApiTS();
|
||||||
|
|
||||||
|
// 恢复自定义文件
|
||||||
|
if (customFiles.length > 0) {
|
||||||
|
restoreCustomFiles(customFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证生成的文件
|
||||||
|
if (!validateGeneratedFiles()) {
|
||||||
|
logWarning('文件验证发现问题,但生成过程已完成');
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalTime = Date.now() - startTime;
|
||||||
|
logSuccess(`API 客户端代码生成完成!总耗时: ${totalTime}ms`);
|
||||||
|
logSuccess('生成的文件位于 src/lib/api/ 目录');
|
||||||
|
|
||||||
|
if (customFiles.length > 0) {
|
||||||
|
logInfo('自定义文件已保持不变,避免覆盖手动配置');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
const totalTime = Date.now() - startTime;
|
||||||
|
logError(`脚本执行失败 (${totalTime}ms): ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行主函数
|
||||||
|
if (require.main === module) {
|
||||||
|
main();
|
||||||
|
}
|
||||||
1
crop-x-new/scripts/openapi.json
Normal file
1
crop-x-new/scripts/openapi.json
Normal file
File diff suppressed because one or more lines are too long
70
crop-x-new/scripts/setup-dev-tools.js
Normal file
70
crop-x-new/scripts/setup-dev-tools.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
// 读取开发工具配置
|
||||||
|
const configPath = path.join(__dirname, '../.dev-tools-config.json');
|
||||||
|
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||||
|
|
||||||
|
// 获取命令行参数
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const enableAll = args.includes('--enable');
|
||||||
|
const disableAll = args.includes('--disable');
|
||||||
|
|
||||||
|
console.log('🔧 开发工具设置脚本');
|
||||||
|
console.log('====================');
|
||||||
|
|
||||||
|
// 更新配置文件
|
||||||
|
function updateConfig(config) {
|
||||||
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||||
|
console.log('✅ 配置文件已更新');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查工具状态
|
||||||
|
function checkToolStatus(toolName, toolConfig) {
|
||||||
|
return toolConfig.enabled ? '✅ 已启用' : '❌ 已禁用';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置工具状态
|
||||||
|
function setToolStatus(toolName, enabled) {
|
||||||
|
config.tools[toolName].enabled = enabled;
|
||||||
|
const status = enabled ? '启用' : '禁用';
|
||||||
|
console.log(`${enabled ? '✅' : '❌'} ${toolName}: ${status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主逻辑
|
||||||
|
if (enableAll) {
|
||||||
|
console.log('🔓 启用所有开发工具...');
|
||||||
|
Object.keys(config.tools).forEach(toolName => {
|
||||||
|
setToolStatus(toolName, true);
|
||||||
|
});
|
||||||
|
updateConfig(config);
|
||||||
|
console.log('\n🎉 所有开发工具已启用!运行以下命令使用:');
|
||||||
|
console.log(' npm run lint # ESLint检查');
|
||||||
|
console.log(' npm run lint:fix # ESLint自动修复');
|
||||||
|
console.log(' npm run format # Prettier格式化');
|
||||||
|
console.log(' npm run format:check # Prettier检查');
|
||||||
|
} else if (disableAll) {
|
||||||
|
console.log('🔒 禁用所有开发工具...');
|
||||||
|
Object.keys(config.tools).forEach(toolName => {
|
||||||
|
setToolStatus(toolName, false);
|
||||||
|
});
|
||||||
|
updateConfig(config);
|
||||||
|
console.log('\n🛌 所有开发工具已禁用!');
|
||||||
|
} else {
|
||||||
|
console.log('📊 当前开发工具状态:');
|
||||||
|
Object.entries(config.tools).forEach(([toolName, toolConfig]) => {
|
||||||
|
console.log(` ${checkToolStatus(toolName, toolConfig)} ${toolName} - ${toolConfig.description}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('\n📖 使用说明:');
|
||||||
|
console.log(' npm run scripts:setup # 查看当前状态');
|
||||||
|
console.log(' npm run scripts:enable # 启用所有工具');
|
||||||
|
console.log(' npm run scripts:disable # 禁用所有工具');
|
||||||
|
console.log('\n💡 提示:也可以直接编辑 .dev-tools-config.json 文件来单独控制每个工具');
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function CustomersPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">客户信息</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/basic/customers
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function MaterialsPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">物料信息</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/basic/materials
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
18
crop-x-new/src/app/(app)/agricultural-asset/basic/page.tsx
Normal file
18
crop-x-new/src/app/(app)/agricultural-asset/basic/page.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function BasicPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">基础信息管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/basic
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function SuppliersPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">供应商信息</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/basic/suppliers
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ToolsPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">农具信息</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/basic/tools
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ArchivePage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">设备档案</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/equipment/archive
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function DepreciationPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">设备折旧</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/equipment/depreciation
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function DispatchPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">设备调度</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/equipment/dispatch
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function DisposalPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">设备处置</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/equipment/disposal
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function MaintenancePage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">设备维护</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/equipment/maintenance
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function EquipmentPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">农资农具管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/equipment
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function CheckPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">库存盘点</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/inventory/check
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function DetailPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">库存明细</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/inventory/detail
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function InPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">入库管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/inventory/in
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function LocationPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">库位管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/inventory/location
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function InventoryPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">库存管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/inventory
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function SuggestPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">补货建议</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/inventory/suggest
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function WarningPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">库存预警</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/inventory/warning
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
7
crop-x-new/src/app/(app)/agricultural-asset/layout.tsx
Normal file
7
crop-x-new/src/app/(app)/agricultural-asset/layout.tsx
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export default function AgriculturalAssetLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return <>{children}</>
|
||||||
|
}
|
||||||
18
crop-x-new/src/app/(app)/agricultural-asset/page.tsx
Normal file
18
crop-x-new/src/app/(app)/agricultural-asset/page.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function AgriculturalAssetPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">农业资产管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function OrderPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">采购订单</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/purchase/order
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function PurchasePage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">采购管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/purchase
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function PlanPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">采购计划</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/purchase/plan
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ConsumptionPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">消耗报表</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/report/consumption
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function InventoryReportPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">库存报表</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/report/inventory
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function OverviewPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">总览报表</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/report/overview
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
18
crop-x-new/src/app/(app)/agricultural-asset/report/page.tsx
Normal file
18
crop-x-new/src/app/(app)/agricultural-asset/report/page.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ReportPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">可视化报表</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/report
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ApplyPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">领用申请</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/requisition/apply
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ApprovalPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">领用审批</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/requisition/approval
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function CheckoutPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">领用发放</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/requisition/checkout
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function RequisitionPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">物资领用</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/requisition
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function RecordPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">领用记录</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/requisition/record
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function HistoryPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">归还历史</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/return/history
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
18
crop-x-new/src/app/(app)/agricultural-asset/return/page.tsx
Normal file
18
crop-x-new/src/app/(app)/agricultural-asset/return/page.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ReturnPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">物资归还</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/return
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ProcessPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">归还处理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/return/process
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function RegisterPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">归还登记</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/return/register
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function SettlementPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">归还结算</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-asset/return/settlement
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ClassificationPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">农机分类管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/archive/classification
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { FileText } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function AgriculturalMachineryEntryPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<FileText className="w-6 h-6 text-blue-600" />
|
||||||
|
<h2 className="text-xl font-semibold">农机录入维护</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机设备信息录入、编辑和维护管理界面。支持农机基本信息、技术参数、购置信息等全面管理。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/archive/entry
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 农机设备信息录入、档案编辑、状态更新、设备台账管理
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Package } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function ArchivePage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Package className="w-6 h-6 text-blue-600" />
|
||||||
|
<h2 className="text-xl font-semibold">农机档案</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机档案管理模块用于管理农业机械的基础信息和档案资料。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/archive
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong>农机信息录入、分类管理、二维码生成等
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { QrCode } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function AgriculturalMachineryQrCodePage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<QrCode className="w-6 h-6 text-purple-600" />
|
||||||
|
<h2 className="text-xl font-semibold">农机二维码管理</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机设备二维码生成和管理平台。支持设备身份识别、信息追溯、移动端扫描查询等功能。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/archive/qrcode
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 二维码生成、批量打印、扫描验证、设备信息追溯
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function AnalysisPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">作业数据分析</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/data-analysis/analysis
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ComparisonPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">历史数据对比</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/data-analysis/comparison
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { PieChart } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function DataAnalysisPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<PieChart className="w-6 h-6 text-cyan-600" />
|
||||||
|
<h2 className="text-xl font-semibold">数据管理与分析报告</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
数据管理与分析报告模块用于农机作业数据的分析、统计和报告生成。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/data-analysis
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong>作业数据分析、历史数据对比、报告生成等
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { User } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function DriverInfoManagementPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<User className="w-6 h-6 text-orange-600" />
|
||||||
|
<h2 className="text-xl font-semibold">驾驶员信息管理</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机驾驶员档案信息管理系统。包括驾驶员基本信息、资质证书、培训记录、考核情况等。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/driver-archive/info
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 驾驶员档案管理、资质认证、培训记录、证书到期提醒
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { User } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function DriverArchivePage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<User className="w-6 h-6 text-green-600" />
|
||||||
|
<h2 className="text-xl font-semibold">驾驶员档案</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
驾驶员档案管理模块用于管理农机驾驶员的基本信息、资质认证和工作记录。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/driver-archive
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong>驾驶员信息管理、资质审核、任务分配等
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Calendar } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function DriverTaskManagementPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Calendar className="w-6 h-6 text-indigo-600" />
|
||||||
|
<h2 className="text-xl font-semibold">驾驶员任务管理</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
驾驶员作业任务分配和执行管理系统。支持任务派发、进度跟踪、绩效评估等功能。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/driver-archive/task
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 任务分配、作业安排、进度监控、绩效考核、工时统计
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
35
crop-x-new/src/app/(app)/agricultural-machinery/error.tsx
Normal file
35
crop-x-new/src/app/(app)/agricultural-machinery/error.tsx
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
|
export default function AgriculturalMachineryError({
|
||||||
|
error,
|
||||||
|
reset,
|
||||||
|
}: {
|
||||||
|
error: Error & { digest?: string }
|
||||||
|
reset: () => void
|
||||||
|
}) {
|
||||||
|
useEffect(() => {
|
||||||
|
console.error('农机管理系统错误:', error)
|
||||||
|
}, [error])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="text-6xl mb-4">🚙</div>
|
||||||
|
<h2 className="text-2xl font-bold text-red-800 mb-4">
|
||||||
|
农机系统出现了错误
|
||||||
|
</h2>
|
||||||
|
<p className="text-red-600 mb-6">
|
||||||
|
{error.message || '未知系统错误'}
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
onClick={reset}
|
||||||
|
className="px-6 py-3 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors"
|
||||||
|
>
|
||||||
|
重新加载
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function AlertRulesPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">故障预警规则</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/fault-diagnosis/alert-rules
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function HealthPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">设备健康管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/fault-diagnosis/health
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Zap } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function FaultDiagnosisPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Zap className="w-6 h-6 text-red-600" />
|
||||||
|
<h2 className="text-xl font-semibold">远程诊断与故障预警</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
远程诊断与故障预警模块用于农机设备的健康监测、故障预警和远程诊断。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/fault-diagnosis
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong>故障预警规则、预警管理、设备健康监控等
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function ParameterPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">设备参数监控</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/fault-diagnosis/parameter
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function WarningPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">故障预警管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/fault-diagnosis/warning
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export default function AgriculturalMachineryLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode
|
||||||
|
}) {
|
||||||
|
return <>{children}</>
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Cog } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function LoadDeviceManagementPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Cog className="w-6 h-6 text-red-600" />
|
||||||
|
<h2 className="text-xl font-semibold">负载设备管理</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机负载设备的日常管理和维护系统。支持设备状态监控、维护计划、备件管理等。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/load-management/device
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 设备台账、维护管理、故障记录、备件库存、状态监控
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Database } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function LoadDeviceLibraryPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Database className="w-6 h-6 text-emerald-600" />
|
||||||
|
<h2 className="text-xl font-semibold">负载设备库</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机负载设备信息库管理系统。建立完整的负载设备档案,支持设备查询和对比分析。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/load-management/library
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 设备信息库、技术规格、性能参数、设备选型推荐
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Settings } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function LoadManagementPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Settings className="w-6 h-6 text-orange-600" />
|
||||||
|
<h2 className="text-xl font-semibold">农机负载管理</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机负载管理模块用于管理农机设备的负载配置、参数设置和设备库管理。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/load-management
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong>负载类型管理、参数配置、设备库管理等
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Settings } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function LoadParameterManagementPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Settings className="w-6 h-6 text-amber-600" />
|
||||||
|
<h2 className="text-xl font-semibold">负载参数管理</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机负载设备参数配置和优化管理。支持作业参数调整、性能优化、标准配置等。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/load-management/parameter
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 参数配置、性能调优、作业标准设置、参数模板管理
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Package } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function LoadTypeManagementPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Package className="w-6 h-6 text-cyan-600" />
|
||||||
|
<h2 className="text-xl font-semibold">负载类型管理</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机负载设备类型分类和管理系统。支持播种、施肥、收割等各类作业负载的类型定义。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/load-management/type
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 负载类型定义、作业分类、设备规格配置、类型参数设置
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
10
crop-x-new/src/app/(app)/agricultural-machinery/loading.tsx
Normal file
10
crop-x-new/src/app/(app)/agricultural-machinery/loading.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
export default function AgriculturalMachineryLoading() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-green-600 mx-auto mb-4"></div>
|
||||||
|
<p className="text-gray-600">正在加载农机管理系统...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { MapPin } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function RealTimeLocationMonitoringPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<MapPin className="w-6 h-6 text-blue-600" />
|
||||||
|
<h2 className="text-xl font-semibold">实时定位监控</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机设备实时GPS定位和轨迹监控系统。提供地图可视化、位置追踪、历史轨迹回放等功能。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/monitoring/location
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> GPS定位、地图显示、实时轨迹、位置历史、电子围栏
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { BarChart3 } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function OperationDataMonitoringPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<BarChart3 className="w-6 h-6 text-orange-600" />
|
||||||
|
<h2 className="text-xl font-semibold">作业数据监控</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机作业数据采集和分析监控。实时收集作业数据,监控作业质量和效率指标。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/monitoring/operation
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 数据采集、作业监控、质量分析、效率统计、报表生成
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Navigation } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function MonitoringPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Navigation className="w-6 h-6 text-purple-600" />
|
||||||
|
<h2 className="text-xl font-semibold">设备实时监控与定位</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
设备实时监控与定位模块用于实时监控农机设备的位置、状态和作业数据。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/monitoring
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong>实时定位监控、作业状态监控、数据监控等
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Activity } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function WorkStatusMonitoringPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Activity className="w-6 h-6 text-green-600" />
|
||||||
|
<h2 className="text-xl font-semibold">作业状态监控</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
农机设备作业状态实时监控系统。跟踪设备运行状态、作业进度、工作效率等关键指标。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/monitoring/status
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong> 状态监控、作业跟踪、效率分析、异常报警、状态统计
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
93
crop-x-new/src/app/(app)/agricultural-machinery/page.tsx
Normal file
93
crop-x-new/src/app/(app)/agricultural-machinery/page.tsx
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export default function AgriculturalMachineryPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="bg-white rounded-lg shadow p-6">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-800 mb-4">
|
||||||
|
智能农机管理系统
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-600 mb-6">
|
||||||
|
管理农机设备档案、监控实时状态、优化调度方案
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
<Link
|
||||||
|
href="/agricultural-machinery/archive/machinery-entry"
|
||||||
|
className="block p-4 bg-green-50 rounded-lg hover:bg-green-100 transition-colors"
|
||||||
|
>
|
||||||
|
<h3 className="font-semibold text-green-900 mb-2">
|
||||||
|
📋 农机档案录入与维护
|
||||||
|
</h3>
|
||||||
|
<p className="text-green-700 text-sm">
|
||||||
|
农机设备信息管理
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
href="/agricultural-machinery/monitoring/real-time-location-tracking"
|
||||||
|
className="block p-4 bg-blue-50 rounded-lg hover:bg-blue-100 transition-colors"
|
||||||
|
>
|
||||||
|
<h3 className="font-semibold text-blue-900 mb-2">
|
||||||
|
📍 实时位置追踪
|
||||||
|
</h3>
|
||||||
|
<p className="text-blue-700 text-sm">
|
||||||
|
农机设备定位监控
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
href="/agricultural-machinery/scheduling/task-assignment"
|
||||||
|
className="block p-4 bg-purple-50 rounded-lg hover:bg-purple-100 transition-colors"
|
||||||
|
>
|
||||||
|
<h3 className="font-semibold text-purple-900 mb-2">
|
||||||
|
📅 任务分配
|
||||||
|
</h3>
|
||||||
|
<p className="text-purple-700 text-sm">
|
||||||
|
农机作业任务分配
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
|
<div className="bg-white rounded-lg shadow p-6">
|
||||||
|
<h3 className="text-lg font-semibold text-gray-800 mb-4">
|
||||||
|
📊 农机状态概览
|
||||||
|
</h3>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-gray-600">运行中</span>
|
||||||
|
<span className="text-green-600 font-semibold">12 台</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-gray-600">空闲中</span>
|
||||||
|
<span className="text-gray-600 font-semibold">8 台</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<span className="text-gray-600">维护中</span>
|
||||||
|
<span className="text-yellow-600 font-semibold">3 台</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bg-white rounded-lg shadow p-6">
|
||||||
|
<h3 className="text-lg font-semibold text-gray-800 mb-4">
|
||||||
|
🔧 快速操作
|
||||||
|
</h3>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<button className="w-full px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700 transition-colors">
|
||||||
|
添加新农机
|
||||||
|
</button>
|
||||||
|
<button className="w-full px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors">
|
||||||
|
生成报表
|
||||||
|
</button>
|
||||||
|
<button className="w-full px-4 py-2 bg-purple-600 text-white rounded hover:bg-purple-700 transition-colors">
|
||||||
|
批量操作
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function CockpitPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">作业驾驶舱</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/precision-operation/cockpit
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function DispatchPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">作业计划调度</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/precision-operation/dispatch
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
import { Target } from 'lucide-react';
|
||||||
|
|
||||||
|
export default function PrecisionOperationPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<div className="flex items-center gap-3 mb-4">
|
||||||
|
<Target className="w-6 h-6 text-indigo-600" />
|
||||||
|
<h2 className="text-xl font-semibold">精准作业管理与支持</h2>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<p className="text-muted-foreground">
|
||||||
|
精准作业管理与支持模块用于管理农机的精准作业、路径规划和作业调度。
|
||||||
|
</p>
|
||||||
|
<div className="p-3 bg-muted rounded-lg">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/precision-operation
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mt-1">
|
||||||
|
<strong>主要功能:</strong>作业记录管理、路径规划、作业调度、作业驾驶舱等
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function RecordPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">作业记录管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/precision-operation/record
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function RoutePage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">路径规划管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/precision-operation/route
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
|
export default function AssignmentPage() {
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<Card className="p-6">
|
||||||
|
<h2 className="text-xl font-semibold">任务分配管理</h2>
|
||||||
|
<div className="p-3 bg-muted rounded-lg mt-3">
|
||||||
|
<p className="text-sm">
|
||||||
|
<strong>页面路径:</strong> /agricultural-machinery/scheduling/assignment
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user