diff --git a/.env.local b/.env.local index 6004804..a52ecae 100644 --- a/.env.local +++ b/.env.local @@ -4,8 +4,8 @@ NODE_ENV=development VITE_DEV=true # 请求路径 -# VITE_BASE_URL='http://192.168.2.21:48080' -VITE_BASE_URL='https://backstageapi.yolozs.com' +VITE_BASE_URL='http://192.168.2.22:48080' +# VITE_BASE_URL='https://backstageapi.yolozs.com' # VITE_BASE_URL='https://testapi.tknb.net' # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务 @@ -30,7 +30,11 @@ VITE_BASE_PATH=/ VITE_MALL_H5_DOMAIN='http://localhost:3000' # 验证码的开关 -VITE_APP_CAPTCHA_ENABLE=false +VITE_APP_CAPTCHA_ENABLE=true + +# Turnstile 站点密钥(生产 Key,需要在 Cloudflare 添加 localhost 到域名白名单) +VITE_APP_TURNSTILE_SITE_KEY=0x4AAAAAACYSAf0bQMQ347Pz +# VITE_APP_TURNSTILE_SITE_KEY=1x00000000000000000000AA # GoView域名 VITE_GOVIEW_URL='http://127.0.0.1:3000' \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..bb4e7fa --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,233 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +This is **yudao-ui-admin-vue3**, a Vue 3 admin dashboard built with Vite, TypeScript, and Element Plus. It's part of the 芋道 (Yudao) open-source admin system that supports multi-tenant SaaS scenarios and integrates with Spring Boot/Spring Cloud backends. + +## Development Commands + +### Setup +```bash +pnpm install # Install dependencies (pnpm is required, version >=8.6.0) +``` + +### Development +```bash +pnpm dev # Start dev server with env.local environment +pnpm dev-server # Start dev server with dev environment +pnpm ts:check # Run TypeScript type checking +``` + +### Build +```bash +pnpm build:local # Build for local environment +pnpm build:dev # Build for dev environment +pnpm build:test # Build for test environment +pnpm build:stage # Build for staging environment +pnpm build:prod # Build for production environment +``` + +### Preview +```bash +pnpm serve:dev # Preview dev build +pnpm serve:prod # Preview production build +pnpm preview # Build local and preview +``` + +### Linting & Formatting +```bash +pnpm lint:eslint # Fix ESLint issues in .js, .ts, .vue files +pnpm lint:format # Format code with Prettier +pnpm lint:style # Fix Stylelint issues in styles +``` + +### Cleanup +```bash +pnpm clean # Remove node_modules +pnpm clean:cache # Clear node_modules cache +``` + +## Architecture + +### Technology Stack +- **Framework**: Vue 3.5.12 (Composition API) +- **Build Tool**: Vite 5.1.4 +- **UI Library**: Element Plus 2.9.1 +- **Language**: TypeScript 5.3.3 +- **State Management**: Pinia 2.1.7 with persistence (pinia-plugin-persistedstate) +- **Router**: Vue Router 4.4.5 +- **I18n**: Vue I18n 9.10.2 +- **HTTP Client**: Axios 1.9.0 +- **CSS Framework**: UnoCSS 0.58.5 +- **Icons**: Iconify 3.1.1 + +### Directory Structure + +``` +src/ +├── api/ # API service layer organized by business modules +│ ├── login/ # Authentication APIs +│ ├── system/ # System management (users, roles, menus, etc.) +│ ├── bpm/ # Business Process Management (workflow) +│ ├── infra/ # Infrastructure (code gen, files, jobs, etc.) +│ ├── pay/ # Payment system +│ ├── mall/ # E-commerce/Mall system +│ ├── crm/ # Customer Relationship Management +│ ├── erp/ # Enterprise Resource Planning +│ ├── ai/ # AI/LLM features +│ └── mp/ # WeChat Official Account +├── assets/ # Static assets (images, svgs) +├── components/ # Global reusable components +├── config/ # Configuration files +├── directives/ # Custom Vue directives +├── hooks/ # Composable functions +├── layout/ # Layout components +├── locales/ # I18n translation files +├── plugins/ # Plugin setup (Element Plus, UnoCSS, etc.) +├── router/ # Vue Router configuration +├── store/ # Pinia stores +│ └── modules/ # Store modules (user, permission, dict, etc.) +├── styles/ # Global styles (SCSS) +├── types/ # TypeScript type definitions +├── utils/ # Utility functions +├── views/ # Page components organized by features +├── App.vue # Root component +├── main.ts # Application entry point +└── permission.ts # Route permission guard +``` + +### Application Bootstrap (src/main.ts) + +The application initializes in this order: +1. **I18n** setup (async - loads translations) +2. **Pinia** store setup +3. **Global components** registration +4. **Element Plus** setup +5. **Form Create** (form builder) setup +6. **Router** setup +7. **Directives** (auth, mounted-focus) +8. **VueDOMPurifyHTML** (XSS protection for v-html) + +### Permission & Route System (src/permission.ts) + +- **Dynamic Route Loading**: Routes are fetched from backend based on user permissions +- **Route Guards**: + - Checks authentication token before each route + - Loads user info and permissions on first access + - Loads dictionary data for the entire app + - Dynamically adds authorized routes using `router.addRoute()` +- **White List**: `/login`, `/social-login`, `/auth-redirect`, `/bind`, `/register`, `/oauthLogin/gitee` + +### State Management Pattern + +Stores are located in `src/store/modules/` and use Pinia: +- `user.ts` - User information and authentication +- `permission.ts` - User permissions and dynamic routes +- `dict.ts` - System dictionaries (cached) +- Store modules use the "WithOut" pattern for access outside setup: `useUserStoreWithOut()` + +### API Layer Pattern + +- APIs are organized by business domain in `src/api/` +- Each module has an `index.ts` (API functions) and `types.ts` (TypeScript interfaces) +- Axios is configured in `src/config/axios/` with interceptors for auth and error handling +- API calls should use the centralized request service, not raw axios + +### Auto-Import System + +The project uses unplugin-auto-import and unplugin-vue-components: +- Vue APIs (ref, computed, etc.) are auto-imported +- Element Plus components are auto-imported +- Custom composables from hooks are auto-imported +- Generated types are in `src/types/auto-imports.d.ts` and `src/types/auto-components.d.ts` + +### Form Builder Integration + +- Uses `@form-create/element-ui` and `@form-create/designer` for dynamic form building +- BPMN workflow designer uses `bpmn-js` and `bpmn-js-properties-panel` + +### Environment Configuration + +- Environment files: `.env`, `.env.local`, `.env.dev`, `.env.test`, `.env.stage`, `.env.prod` +- Key variables: + - `VITE_BASE_PATH` - Base URL path + - `VITE_BASE_URL` - API base URL + - `VITE_PORT` - Dev server port + - `VITE_OUT_DIR` - Build output directory + - `VITE_DROP_CONSOLE` - Remove console.log in production + +### Build Configuration + +- **Code Splitting**: + - `echarts` is split into separate chunk + - `@form-create/element-ui` is split separately + - `@form-create/designer` is split separately +- **Minification**: Uses Terser +- **Memory**: Build uses `--max_old_space_size=4096` for large builds + +### Multi-Tenant (SaaS) Support + +This system has built-in multi-tenant functionality: +- Tenant management in system modules +- Tenant packages with customizable menu/permission configurations +- APIs should be tenant-aware + +## Development Guidelines + +### Path Aliases + +Use `@/` for imports, which resolves to `src/`: +```typescript +import { useUserStore } from '@/store/modules/user' +``` + +### TypeScript + +- `noImplicitAny` is disabled - type annotations are not strictly required +- Use interfaces from `src/api/*/types.ts` for API request/response types + +### I18n + +- Translation files are in `src/locales/` +- Use the `useI18n()` composable (auto-imported) +- Support for Chinese and English + +### Component Development + +- Global components in `src/components/` are auto-registered +- Use Element Plus components (auto-imported, no manual import needed) +- DiyEditor mobile components are excluded from auto-import + +### Icons + +- SVG icons are in `src/assets/svgs/` +- Use Iconify for icon sets +- SVG icons are registered with `icon-[dir]-[name]` pattern + +### Styling + +- SCSS is the preprocessor +- Global variables are in `src/styles/variables.scss` (auto-injected) +- UnoCSS is used for atomic/utility CSS + +### Security + +- XSS protection via `vue-dompurify-html` for v-html directives +- Auth tokens managed in `src/utils/auth` +- Permission directives for button-level access control + +## Important Notes + +- **Node.js**: Requires >= 16.0.0 +- **pnpm**: Must use pnpm >= 8.6.0 (not npm or yarn) +- **Backend**: Designed to work with Spring Boot (single) or Spring Cloud (microservices) backend +- **Route Debugging**: If routes aren't appearing, check the permission store and backend API responses +- **Dictionary Loading**: System dictionaries are loaded once on login and cached in the dict store + +## Related Documentation + +- Backend API docs (Swagger): Available at `/admin-api/swagger-ui.html` on backend server +- Official docs: https://doc.iocoder.cn +- Demo: http://dashboard-vue3.yudao.iocoder.cn diff --git a/index.html b/index.html index a913098..09ff839 100644 --- a/index.html +++ b/index.html @@ -146,6 +146,7 @@ + diff --git a/src/api/login/index.ts b/src/api/login/index.ts index 7d7d407..71fa302 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -1,5 +1,5 @@ import request from '@/config/axios' -import type { RegisterVO, UserLoginVO } from './types' +import type { RegisterVO, TenantRegisterVO, UserLoginVO } from './types' export interface SmsCodeVO { mobile: string @@ -16,11 +16,14 @@ export const login = (data: UserLoginVO) => { return request.post({ url: '/system/auth/login', data }) } -// 注册 +// 用户注册 export const register = (data: RegisterVO) => { return request.post({ url: '/system/auth/register', data }) } - +// 租户注册 +export const tenantRegister = (data: TenantRegisterVO) => { + return request.post({ url: '/system/tenant/register', data }) +} // 使用租户名,获得租户编号 export const getTenantIdByName = (name: string) => { return request.get({ url: '/system/tenant/get-id-by-name?name=' + name }) diff --git a/src/api/login/types.ts b/src/api/login/types.ts index b5790e6..2f418b8 100644 --- a/src/api/login/types.ts +++ b/src/api/login/types.ts @@ -36,3 +36,12 @@ export type RegisterVO = { password: string captchaVerification: string } + +export type TenantRegisterVO = { + name: string + contactName: string + contactMobile: string + username: string + password: string + captchaVerification: string +} diff --git a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue index 00e887c..802a5bf 100644 --- a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue +++ b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue @@ -32,11 +32,7 @@ - + @@ -47,11 +43,7 @@ icon="el-icon-s-data" @click="elementsAlign('left')" /> --> - + - + - + - + - + - + @@ -122,11 +94,7 @@ icon="el-icon-zoom-out" @click="processZoomOut()" /> --> - + {{ Math.floor(defaultZoom * 10 * 10) + '%' }} @@ -162,32 +130,16 @@ - +
-
+
+
- +
@@ -261,13 +213,13 @@ const props = defineProps({ translations: { // 自定义的翻译文件 type: Object, - default: () => {} + default: () => { } }, additionalModel: [Object, Array], // 自定义model moddleExtension: { // 自定义moddle type: Object, - default: () => {} + default: () => { } }, onlyCustomizeAddi: { type: Boolean, @@ -542,9 +494,8 @@ const setEncoded = (type, data) => { const encodedData = encodeURIComponent(data) return { filename: `${filename}.${type}`, - href: `data:application/${ - type === 'svg' ? 'text/xml' : 'bpmn20-xml' - };charset=UTF-8,${encodedData}`, + href: `data:application/${type === 'svg' ? 'text/xml' : 'bpmn20-xml' + };charset=UTF-8,${encodedData}`, data: data } } @@ -642,7 +593,7 @@ const previewProcessJson = () => { }) } -/* ------------------------------------------------ 芋道源码 methods ------------------------------------------------------ */ +/* ------------------------------------------------ YOLO methods ------------------------------------------------------ */ onMounted(() => { initBpmnModeler() createNewDiagram(props.value) diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 91e1827..e8164eb 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1,5 +1,5 @@ /** - * Created by 芋道源码 + * Created by YOLO * * 枚举类 */ diff --git a/src/views/Login/Login.vue b/src/views/Login/Login.vue index 341ccb0..bee522f 100644 --- a/src/views/Login/Login.vue +++ b/src/views/Login/Login.vue @@ -49,6 +49,8 @@ + + @@ -63,7 +65,7 @@ import { useAppStore } from '@/store/modules/app' import { ThemeSwitch } from '@/layout/components/ThemeSwitch' import { LocaleDropdown } from '@/layout/components/LocaleDropdown' -import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm } from './components' +import { LoginForm, MobileForm, QrCodeForm, RegisterForm, SSOLoginVue, ForgetPasswordForm, TenantRegisterForm } from './components' defineOptions({ name: 'Login' }) diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 02a0bf8..53e8d6e 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -50,46 +50,35 @@ - + + + + + + - {{ t('login.otherLogin') }} + @@ -18,23 +10,15 @@ - + - + @@ -42,19 +26,11 @@ - + @@ -229,7 +194,7 @@ onMounted(async () => { })