commit
22252db5d4
@ -0,0 +1,17 @@ |
||||
# Editor configuration, see https://editorconfig.org |
||||
root = true |
||||
|
||||
[*] |
||||
charset = utf-8 |
||||
indent_style = space |
||||
indent_size = 2 |
||||
insert_final_newline = true |
||||
trim_trailing_whitespace = true |
||||
|
||||
[*.ts] |
||||
quote_type = single |
||||
ij_typescript_use_double_quotes = false |
||||
|
||||
[*.md] |
||||
max_line_length = off |
||||
trim_trailing_whitespace = false |
@ -0,0 +1,8 @@ |
||||
.git/ |
||||
.idea/ |
||||
node_modules/ |
||||
dist/ |
||||
.angular/ |
||||
|
||||
|
||||
|
@ -0,0 +1,4 @@ |
||||
{ |
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 |
||||
"recommendations": ["angular.ng-template"] |
||||
} |
@ -0,0 +1,20 @@ |
||||
{ |
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |
||||
"version": "0.2.0", |
||||
"configurations": [ |
||||
{ |
||||
"name": "ng serve", |
||||
"type": "chrome", |
||||
"request": "launch", |
||||
"preLaunchTask": "npm: start", |
||||
"url": "http://localhost:4200/" |
||||
}, |
||||
{ |
||||
"name": "ng test", |
||||
"type": "chrome", |
||||
"request": "launch", |
||||
"preLaunchTask": "npm: test", |
||||
"url": "http://localhost:9876/debug.html" |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,42 @@ |
||||
{ |
||||
// For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 |
||||
"version": "2.0.0", |
||||
"tasks": [ |
||||
{ |
||||
"type": "npm", |
||||
"script": "start", |
||||
"isBackground": true, |
||||
"problemMatcher": { |
||||
"owner": "typescript", |
||||
"pattern": "$tsc", |
||||
"background": { |
||||
"activeOnStart": true, |
||||
"beginsPattern": { |
||||
"regexp": "(.*?)" |
||||
}, |
||||
"endsPattern": { |
||||
"regexp": "bundle generation complete" |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
"type": "npm", |
||||
"script": "test", |
||||
"isBackground": true, |
||||
"problemMatcher": { |
||||
"owner": "typescript", |
||||
"pattern": "$tsc", |
||||
"background": { |
||||
"activeOnStart": true, |
||||
"beginsPattern": { |
||||
"regexp": "(.*?)" |
||||
}, |
||||
"endsPattern": { |
||||
"regexp": "bundle generation complete" |
||||
} |
||||
} |
||||
} |
||||
} |
||||
] |
||||
} |
@ -0,0 +1,59 @@ |
||||
# CgWeb |
||||
|
||||
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0. |
||||
|
||||
## Development server |
||||
|
||||
To start a local development server, run: |
||||
|
||||
```bash |
||||
ng serve |
||||
``` |
||||
|
||||
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. |
||||
|
||||
## Code scaffolding |
||||
|
||||
Angular CLI includes powerful code scaffolding tools. To generate a new component, run: |
||||
|
||||
```bash |
||||
ng generate component component-name |
||||
``` |
||||
|
||||
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: |
||||
|
||||
```bash |
||||
ng generate --help |
||||
``` |
||||
|
||||
## Building |
||||
|
||||
To build the project run: |
||||
|
||||
```bash |
||||
ng build |
||||
``` |
||||
|
||||
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. |
||||
|
||||
## Running unit tests |
||||
|
||||
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: |
||||
|
||||
```bash |
||||
ng test |
||||
``` |
||||
|
||||
## Running end-to-end tests |
||||
|
||||
For end-to-end (e2e) testing, run: |
||||
|
||||
```bash |
||||
ng e2e |
||||
``` |
||||
|
||||
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. |
||||
|
||||
## Additional Resources |
||||
|
||||
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. |
@ -0,0 +1,145 @@ |
||||
{ |
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json", |
||||
"version": 1, |
||||
"newProjectRoot": "projects", |
||||
"projects": { |
||||
"cg-web": { |
||||
"projectType": "application", |
||||
"schematics": { |
||||
"@schematics/angular:component": { |
||||
"style": "scss" |
||||
} |
||||
}, |
||||
"root": "", |
||||
"sourceRoot": "src", |
||||
"prefix": "app", |
||||
"architect": { |
||||
"build": { |
||||
"builder": "@angular-devkit/build-angular:application", |
||||
"options": { |
||||
"outputPath": "dist/cg-web", |
||||
"index": "src/index.html", |
||||
"browser": "src/main.ts", |
||||
"polyfills": [ |
||||
"zone.js" |
||||
], |
||||
"tsConfig": "tsconfig.app.json", |
||||
"inlineStyleLanguage": "scss", |
||||
"assets": [ |
||||
"src/favicon.ico", |
||||
"src/assets", |
||||
{ |
||||
"glob": "**/*", |
||||
"input": "public" |
||||
}, |
||||
{ |
||||
"glob": "**/*", |
||||
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", |
||||
"output": "/assets/" |
||||
} |
||||
], |
||||
"styles": [ |
||||
"src/theme.less", |
||||
"src/styles.scss" |
||||
], |
||||
"scripts": [], |
||||
"server": "src/main.server.ts", |
||||
"outputMode": "server", |
||||
"ssr": { |
||||
"entry": "src/server.ts" |
||||
} |
||||
}, |
||||
"configurations": { |
||||
"prod": { |
||||
"budgets": [ |
||||
{ |
||||
"type": "initial", |
||||
"maximumWarning": "500kb", |
||||
"maximumError": "2mb" |
||||
}, |
||||
{ |
||||
"type": "anyComponentStyle", |
||||
"maximumWarning": "2kb", |
||||
"maximumError": "4kb" |
||||
} |
||||
], |
||||
"outputHashing": "all", |
||||
"fileReplacements": [ |
||||
{ |
||||
"replace": "src/environments/environment.ts", |
||||
"with": "src/environments/environment.prod.ts" |
||||
} |
||||
] |
||||
}, |
||||
"dev": { |
||||
"budgets": [ |
||||
{ |
||||
"type": "initial", |
||||
"maximumWarning": "500kb", |
||||
"maximumError": "2mb" |
||||
}, |
||||
{ |
||||
"type": "anyComponentStyle", |
||||
"maximumWarning": "2kb", |
||||
"maximumError": "4kb" |
||||
} |
||||
], |
||||
"outputHashing": "all", |
||||
"fileReplacements": [ |
||||
{ |
||||
"replace": "src/environments/environment.ts", |
||||
"with": "src/environments/environment.dev.ts" |
||||
} |
||||
] |
||||
}, |
||||
"development": { |
||||
"optimization": false, |
||||
"extractLicenses": false, |
||||
"sourceMap": true |
||||
} |
||||
}, |
||||
"defaultConfiguration": "production" |
||||
}, |
||||
"serve": { |
||||
"builder": "@angular-devkit/build-angular:dev-server", |
||||
"configurations": { |
||||
"production": { |
||||
"buildTarget": "cg-web:build:production" |
||||
}, |
||||
"development": { |
||||
"buildTarget": "cg-web:build:development" |
||||
} |
||||
}, |
||||
"defaultConfiguration": "development" |
||||
}, |
||||
"extract-i18n": { |
||||
"builder": "@angular-devkit/build-angular:extract-i18n" |
||||
}, |
||||
"test": { |
||||
"builder": "@angular-devkit/build-angular:karma", |
||||
"options": { |
||||
"polyfills": [ |
||||
"zone.js", |
||||
"zone.js/testing" |
||||
], |
||||
"tsConfig": "tsconfig.spec.json", |
||||
"inlineStyleLanguage": "scss", |
||||
"assets": [ |
||||
{ |
||||
"glob": "**/*", |
||||
"input": "public" |
||||
} |
||||
], |
||||
"styles": [ |
||||
"src/styles.scss" |
||||
], |
||||
"scripts": [] |
||||
} |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
"cli": { |
||||
"analytics": "d2267a73-5d6b-4696-b602-6326a9fc0d26" |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,44 @@ |
||||
{ |
||||
"name": "cg-web", |
||||
"version": "0.0.0", |
||||
"scripts": { |
||||
"ng": "ng", |
||||
"start": "ng serve", |
||||
"build": "ng build", |
||||
"watch": "ng build --watch --configuration development", |
||||
"test": "ng test", |
||||
"serve:ssr:cg-web": "node dist/cg-web/server/server.mjs" |
||||
}, |
||||
"private": true, |
||||
"dependencies": { |
||||
"@angular/common": "^19.2.0", |
||||
"@angular/compiler": "^19.2.0", |
||||
"@angular/core": "^19.2.0", |
||||
"@angular/forms": "^19.2.0", |
||||
"@angular/platform-browser": "^19.2.0", |
||||
"@angular/platform-browser-dynamic": "^19.2.0", |
||||
"@angular/platform-server": "^19.2.0", |
||||
"@angular/router": "^19.2.0", |
||||
"@angular/ssr": "^19.2.0", |
||||
"express": "^4.18.2", |
||||
"ng-zorro-antd": "^19.1.0", |
||||
"rxjs": "~7.8.0", |
||||
"tslib": "^2.3.0", |
||||
"zone.js": "~0.15.0" |
||||
}, |
||||
"devDependencies": { |
||||
"@angular-devkit/build-angular": "^19.2.0", |
||||
"@angular/cli": "^19.2.0", |
||||
"@angular/compiler-cli": "^19.2.0", |
||||
"@types/express": "^4.17.17", |
||||
"@types/jasmine": "~5.1.0", |
||||
"@types/node": "^18.18.0", |
||||
"jasmine-core": "~5.6.0", |
||||
"karma": "~6.4.0", |
||||
"karma-chrome-launcher": "~3.2.0", |
||||
"karma-coverage": "~2.2.0", |
||||
"karma-jasmine": "~5.1.0", |
||||
"karma-jasmine-html-reporter": "~2.1.0", |
||||
"typescript": "~5.7.2" |
||||
} |
||||
} |
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1 @@ |
||||
<router-outlet></router-outlet> |
@ -0,0 +1,14 @@ |
||||
import { Component } from '@angular/core'; |
||||
import { RouterOutlet } from '@angular/router'; |
||||
|
||||
@Component({ |
||||
selector: 'app-root', |
||||
standalone: true, |
||||
imports: [RouterOutlet], |
||||
templateUrl: './app.component.html', |
||||
|
||||
styleUrl: './app.component.scss' |
||||
}) |
||||
export class AppComponent { |
||||
title = '超冠体育'; |
||||
} |
@ -0,0 +1,14 @@ |
||||
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core'; |
||||
import { provideServerRendering } from '@angular/platform-server'; |
||||
import { provideServerRouting } from '@angular/ssr'; |
||||
import { appConfig } from './app.config'; |
||||
import { serverRoutes } from './app.routes.server'; |
||||
|
||||
const serverConfig: ApplicationConfig = { |
||||
providers: [ |
||||
provideServerRendering(), |
||||
provideServerRouting(serverRoutes) |
||||
] |
||||
}; |
||||
|
||||
export const config = mergeApplicationConfig(appConfig, serverConfig); |
@ -0,0 +1,27 @@ |
||||
import { ApplicationConfig, provideZoneChangeDetection, importProvidersFrom } from '@angular/core'; |
||||
import {provideRouter} from '@angular/router'; |
||||
|
||||
import { routes } from './app.routes'; |
||||
import { provideClientHydration, withEventReplay } from '@angular/platform-browser'; |
||||
import { zh_CN, provideNzI18n } from 'ng-zorro-antd/i18n'; |
||||
import { registerLocaleData } from '@angular/common'; |
||||
import zh from '@angular/common/locales/zh'; |
||||
import { FormsModule } from '@angular/forms'; |
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; |
||||
import { provideHttpClient, withInterceptors} from '@angular/common/http'; |
||||
import {InterceptorService} from "./utils/Interceptor.service"; |
||||
|
||||
registerLocaleData(zh); |
||||
|
||||
export const appConfig: ApplicationConfig = { |
||||
providers: [ |
||||
provideZoneChangeDetection({ eventCoalescing: true }), |
||||
provideRouter(routes), |
||||
provideClientHydration(withEventReplay()), |
||||
provideNzI18n(zh_CN), |
||||
importProvidersFrom(FormsModule), |
||||
provideAnimationsAsync(), |
||||
provideHttpClient( withInterceptors([InterceptorService]),), |
||||
|
||||
] |
||||
}; |
@ -0,0 +1,8 @@ |
||||
import { RenderMode, ServerRoute } from '@angular/ssr'; |
||||
|
||||
export const serverRoutes: ServerRoute[] = [ |
||||
{ |
||||
path: '**', |
||||
renderMode: RenderMode.Prerender |
||||
} |
||||
]; |
@ -0,0 +1,49 @@ |
||||
import { Routes } from '@angular/router'; |
||||
|
||||
import {Error404Component} from './pages/error/error404/error404.component'; |
||||
import {InitGuardService} from './utils/initGuard.service'; |
||||
import {IndexComponent} from './pages/body/index/index.component'; |
||||
|
||||
export const routes: Routes = [ |
||||
{path: '', pathMatch: 'full', redirectTo: 'admin/index'}, |
||||
{ |
||||
path: 'login', |
||||
loadChildren: () => import('./pages/login/login.routes').then(m => m.LOGIN_ROUTES) |
||||
}, |
||||
{ |
||||
path: 'index', |
||||
loadChildren: () => import('./pages/login/login.routes').then(m => m.LOGIN_ROUTES) |
||||
}, |
||||
{ |
||||
path: 'admin', component: IndexComponent, |
||||
children: [ |
||||
{ |
||||
path: 'index', |
||||
loadChildren: () => import('./pages/index/index.routes').then(m => m.INDEX_ROUTES), |
||||
canActivate: [InitGuardService] |
||||
}, |
||||
{ |
||||
path: 'system', |
||||
loadChildren: () => import('./pages/system/system.routes').then(m => m.SYSTEM_ROUTES), |
||||
canActivate: [InitGuardService] |
||||
}, |
||||
{ |
||||
path: 'account', |
||||
loadChildren: () => import('./pages/account/account.routes').then(m => m.ACCOUNT_ROUTES), |
||||
canActivate: [InitGuardService] |
||||
}, |
||||
{ |
||||
path: 'student', |
||||
loadChildren: () => import('./pages/student/student.routes').then(m => m.STUDENT_ROUTES), |
||||
canActivate: [InitGuardService] |
||||
}, |
||||
] |
||||
}, |
||||
{ |
||||
path: 'error', |
||||
loadChildren: () => import('./pages/error/error.routes').then(m => m.ERROR_ROUTES), |
||||
}, |
||||
{ |
||||
path: '**', component: Error404Component |
||||
}, |
||||
]; |
@ -0,0 +1,13 @@ |
||||
export interface Dictionary { |
||||
codeType: string; |
||||
codeValue: string; |
||||
codeName: string; |
||||
codeDesc: string; |
||||
sortId: number; |
||||
ext1: string; |
||||
ext2: string; |
||||
ext3: string; |
||||
} |
||||
|
||||
export let dictionaryData: Dictionary[] = []; |
||||
|
@ -0,0 +1,5 @@ |
||||
export const USER_TOKEN = 'userToken'; |
||||
export const INIT_FLAG = 'initFlag'; |
||||
export const DATA = 'DATA'; |
||||
export const LOGIN_DATA = 'loginData'; |
||||
|
@ -0,0 +1,6 @@ |
||||
export const backgroundImage = [ |
||||
"./assets/login/1.png", |
||||
"./assets/login/2.png", |
||||
"./assets/login/3.png", |
||||
"./assets/login/4.png"]; |
||||
|
@ -0,0 +1,9 @@ |
||||
export const menuData = [ |
||||
{title: "首页" , selected: true} , |
||||
{title: "商户管理" , selected: false} , |
||||
{title: "数据交易" , selected: false} , |
||||
{title: "产品中心" , selected: false} , |
||||
{title: "账号管理" , selected: false} , |
||||
{title: "营销工具" , selected: false} |
||||
]; |
||||
|
@ -0,0 +1,12 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { CommonModule } from '@angular/common'; |
||||
|
||||
|
||||
|
||||
@NgModule({ |
||||
declarations: [], |
||||
imports: [ |
||||
CommonModule |
||||
] |
||||
}) |
||||
export class AccountModule { } |
@ -0,0 +1,9 @@ |
||||
import { Routes } from '@angular/router'; |
||||
import {SysAccountComponent} from "./sys-account/sys-account.component"; |
||||
import {SysRoleComponent} from "./sys-role/sys-role.component"; |
||||
|
||||
|
||||
export const ACCOUNT_ROUTES: Routes = [ |
||||
{ path: 'sys_account', component: SysAccountComponent}, |
||||
{ path: 'sys_role', component: SysRoleComponent}, |
||||
]; |
@ -0,0 +1,133 @@ |
||||
<form nz-form [formGroup]="searchForm" class="search_form" [nzLayout]="'vertical'"> |
||||
<div nz-row [nzGutter]="24"> |
||||
<div nz-col [nzSpan]="6"> |
||||
<nz-form-item> |
||||
<nz-form-label>用户名</nz-form-label> |
||||
<nz-form-control> |
||||
<input nzSize="large" nz-input formControlName="userName" placeholder="请输入" /> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</div> |
||||
<div nz-col [nzSpan]="6"> |
||||
<nz-form-item> |
||||
<nz-form-label>登录账户</nz-form-label> |
||||
<nz-form-control> |
||||
<input nzSize="large" nz-input formControlName="loginName" placeholder="请输入"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</div> |
||||
<div nz-col [nzSpan]="6"> |
||||
<nz-form-item> |
||||
<nz-form-label>联系方式</nz-form-label> |
||||
<nz-form-control> |
||||
<input nzSize="large" nz-input formControlName="telephone" placeholder="请输入"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</div> |
||||
<div nz-col [nzSpan]="6"> |
||||
<nz-form-item> |
||||
<nz-form-label>账户状态</nz-form-label> |
||||
<nz-form-control> |
||||
<nz-select nzSize="large" formControlName="status" nzAllowClear [nzPlaceHolder]="'请选择'"> |
||||
<nz-option *ngFor="let item of accountStatus" nzValue="{{item.codeValue}}" nzLabel="{{item.codeName}}"></nz-option> |
||||
</nz-select> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</div> |
||||
<div nz-col [nzSpan]="6"> |
||||
<button nz-button [nzType]="'primary'" (click)="searchFormSubmit()">查询</button> |
||||
<button nz-button (click)="searchFormReset()">重置</button> |
||||
<button nz-button [nzType]="'primary'" (click)="showEditAccount(true, null)">创建</button> |
||||
</div> |
||||
</div> |
||||
</form> |
||||
|
||||
<nz-table #basicTable |
||||
[nzScroll]="{ x: '1100px' }" |
||||
[nzBordered]="true" |
||||
[nzFrontPagination]="false" |
||||
[nzShowQuickJumper]="true" |
||||
[nzShowTotal]="totalTemplate" |
||||
[(nzPageIndex)]="tablePageNum" |
||||
(nzPageIndexChange)="queryData()" |
||||
[nzTotal]="tableData.total" |
||||
[nzData]="tableData.list" > |
||||
<thead> |
||||
<tr> |
||||
<th nzWidth="80px">用户名</th> |
||||
<th nzWidth="50px">登录账户</th> |
||||
<th nzWidth="80px">联系方式</th> |
||||
<th nzWidth="50px">创建时间</th> |
||||
<th nzWidth="50px">更新时间</th> |
||||
<th nzRight nzWidth="50px">操作</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<tr *ngFor="let data of basicTable.data"> |
||||
<td>{{data.userName}}</td> |
||||
<td>{{data.loginName}}</td> |
||||
<td>{{data.telephone}}</td> |
||||
<td>{{data.createTime | date: 'yyyy-MM-dd HH:mm'}}</td> |
||||
<td>{{data.updateTime | date: 'yyyy-MM-dd HH:mm'}}</td> |
||||
<td nzRight> |
||||
<a (click)="showEditAccount(false, data)">修改</a> |
||||
<nz-divider nzType="vertical"></nz-divider> |
||||
<a nz-dropdown [nzDropdownMenu]="menu"> |
||||
更多 |
||||
<span nz-icon nzType="down"></span> |
||||
</a> |
||||
<nz-dropdown-menu #menu="nzDropdownMenu"> |
||||
<ul nz-menu nzSelectable> |
||||
<li nz-menu-item *ngIf="data.status == 1"><a (click)="showDisable(data.id)">禁用账户</a></li> |
||||
<li nz-menu-item *ngIf="data.status == 2"><a (click)="showRestore(data.id)">恢复账户</a></li> |
||||
<li nz-menu-item><a (click)="showResetPwd(data.id)">密码重置</a></li> |
||||
<li nz-menu-item nzDanger (click)="showDelData(data.id)">删除</li> |
||||
</ul> |
||||
</nz-dropdown-menu> |
||||
</td> |
||||
</tr> |
||||
</tbody> |
||||
<ng-template #totalTemplate let-total>总计 {{ total }} 条</ng-template> |
||||
</nz-table> |
||||
|
||||
<nz-modal [(nzVisible)]="editAccountVisible" nzTitle="{{editAccountTitle}}" [nzFooter]="null" (nzOnCancel)="closeEditAccount()"> |
||||
<ng-container *nzModalContent> |
||||
<form nz-form [formGroup]="editAccountForm" (ngSubmit)="submitEditAccountForm()"> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>用户名</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="用户名填写有误!"> |
||||
<input nzSize="large" nz-input formControlName="userName"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>登录账户</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="登录账户填写有误!"> |
||||
<input nzSize="large" nz-input formControlName="loginName"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24">联系方式</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24"> |
||||
<input nzSize="large" nz-input formControlName="telephone"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>角色权限</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="角色权限选择有误!"> |
||||
<nz-select nzSize="large" nzShowSearch formControlName="roleId"> |
||||
<nz-option *ngFor="let item of roleData" nzValue="{{item.id}}" nzLabel="{{item.roleName}}"></nz-option> |
||||
</nz-select> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<div nz-flex [nzJustify]="'center'"> |
||||
<button nz-button nzType="primary" class="submit-btn">保存</button> |
||||
</div> |
||||
|
||||
</form> |
||||
</ng-container> |
||||
</nz-modal> |
@ -0,0 +1,15 @@ |
||||
[nz-form-label] { |
||||
overflow: visible; |
||||
} |
||||
button { |
||||
margin-right: 8px; |
||||
} |
||||
.search-area { |
||||
text-align: left; |
||||
} |
||||
.submit-btn { |
||||
width: 150px; |
||||
} |
||||
.search_form { |
||||
margin-bottom: 15px; |
||||
} |
@ -0,0 +1,324 @@ |
||||
import { Component } from '@angular/core'; |
||||
import {FormGroup, NonNullableFormBuilder, ReactiveFormsModule, Validators} from "@angular/forms"; |
||||
import {NzMessageService} from "ng-zorro-antd/message"; |
||||
import {NzModalComponent, NzModalModule, NzModalService} from "ng-zorro-antd/modal"; |
||||
import {DatePipe, NgForOf, NgIf} from "@angular/common"; |
||||
import {NzButtonComponent} from "ng-zorro-antd/button"; |
||||
import {NzColDirective, NzRowDirective} from "ng-zorro-antd/grid"; |
||||
import {NzDividerComponent} from "ng-zorro-antd/divider"; |
||||
import {NzFlexDirective} from "ng-zorro-antd/flex"; |
||||
import {NzFormControlComponent, NzFormDirective, NzFormItemComponent, NzFormLabelComponent} from "ng-zorro-antd/form"; |
||||
import {NzInputDirective} from "ng-zorro-antd/input"; |
||||
import { |
||||
NzTableCellDirective, |
||||
NzTableComponent, NzTableModule, |
||||
NzTbodyComponent, |
||||
NzTheadComponent, |
||||
NzThMeasureDirective, NzTrDirective |
||||
} from "ng-zorro-antd/table"; |
||||
import {NzTreeComponent} from "ng-zorro-antd/tree"; |
||||
import {NzOptionComponent, NzSelectComponent} from "ng-zorro-antd/select"; |
||||
import {NzDropDownModule} from "ng-zorro-antd/dropdown"; |
||||
import {NzIconDirective} from "ng-zorro-antd/icon"; |
||||
import {DictionaryPipe} from "../../../pipes/common/dictionary.pipe"; |
||||
import {Dictionary} from "../../../data/common/dictionary.namespace"; |
||||
import {SysAccountService} from "../../../services/account/sys-account.service"; |
||||
import {RoleService} from '../../../services/system/role.service'; |
||||
|
||||
@Component({ |
||||
selector: 'app-sys-account', |
||||
standalone: true, |
||||
imports: [ |
||||
DatePipe, |
||||
NgForOf, |
||||
NgIf, |
||||
NzButtonComponent, |
||||
NzColDirective, |
||||
NzDividerComponent, |
||||
NzFlexDirective, |
||||
NzFormControlComponent, |
||||
NzFormDirective, |
||||
NzFormItemComponent, |
||||
NzFormLabelComponent, |
||||
NzInputDirective, |
||||
NzModalComponent, |
||||
NzRowDirective, |
||||
NzTableCellDirective, |
||||
NzTableComponent, |
||||
NzTbodyComponent, |
||||
NzThMeasureDirective, |
||||
NzTheadComponent, |
||||
NzTrDirective, |
||||
NzTreeComponent, |
||||
ReactiveFormsModule, |
||||
NzTableModule, |
||||
NzModalModule, |
||||
NzSelectComponent, |
||||
NzOptionComponent, |
||||
NzDropDownModule, |
||||
NzIconDirective, |
||||
DictionaryPipe, |
||||
], |
||||
templateUrl: './sys-account.component.html', |
||||
styleUrl: './sys-account.component.less' |
||||
}) |
||||
export class SysAccountComponent { |
||||
// 表单页数
|
||||
tablePageNum = 1; |
||||
// 表单数据
|
||||
tableData: any = { |
||||
total: 0, |
||||
list: [], |
||||
}; |
||||
accountStatus: Dictionary[] = [] |
||||
// 角色数据
|
||||
roleData: any = []; |
||||
// 搜索表单
|
||||
searchForm: FormGroup; |
||||
// 编辑账户弹出框
|
||||
editAccountVisible = false; |
||||
// 编辑账户表单
|
||||
editAccountForm: FormGroup; |
||||
// 编辑账户标题
|
||||
editAccountTitle = ''; |
||||
|
||||
constructor(private fb: NonNullableFormBuilder, |
||||
private sysAccountService: SysAccountService, |
||||
private roleService: RoleService, |
||||
private message: NzMessageService, |
||||
private modal: NzModalService) { |
||||
// 初始化搜索框
|
||||
this.searchForm = this.fb.group({ |
||||
userName: [''], |
||||
loginName: [''], |
||||
telephone: [''], |
||||
status: [''], |
||||
}); |
||||
|
||||
// 初始化账户表单
|
||||
this.editAccountForm = this.fb.group({ |
||||
id: [''], |
||||
userName: ['', [Validators.required]], |
||||
loginName: ['', [Validators.required]], |
||||
telephone: [''], |
||||
platformCode: [''], |
||||
roleId: ['', [Validators.required]], |
||||
}); |
||||
this.accountStatus = new DictionaryPipe().getDictionaryList("SEC_USER_STATUS"); |
||||
this.queryAllRole(); |
||||
this.queryData(); |
||||
} |
||||
|
||||
/** |
||||
* 获取角色 |
||||
*/ |
||||
queryAllRole() { |
||||
this.roleService.queryAllRole((data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
this.roleData = data['return_data']; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 获取数据 |
||||
*/ |
||||
queryData() { |
||||
this.searchForm.value.pageNum = this.tablePageNum; |
||||
this.searchForm.value.pageSize = 10; |
||||
this.searchForm.value.objectType = 1; |
||||
this.searchForm.value.time = new Date().getTime(); |
||||
this.sysAccountService.queryList(this.searchForm.value, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
this.tableData = data['return_data']; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 搜索表单提交 |
||||
*/ |
||||
searchFormSubmit(): void { |
||||
this.tablePageNum = 1; |
||||
this.queryData(); |
||||
} |
||||
|
||||
/** |
||||
* 搜索表单重置 |
||||
*/ |
||||
searchFormReset(): void { |
||||
this.searchForm.reset(); |
||||
} |
||||
|
||||
/** |
||||
* 打开编辑账户模态框 |
||||
* @param edit 编辑荒唐 true:增加 false:修改 |
||||
* @param data |
||||
*/ |
||||
showEditAccount(edit: boolean, data: any) { |
||||
if (edit) { |
||||
this.editAccountTitle = '创建账户'; |
||||
} else { |
||||
this.editAccountTitle = '修改账户'; |
||||
data['roleId'] = ""+data['roleId'] |
||||
this.editAccountForm.patchValue(data); |
||||
} |
||||
this.editAccountVisible = true; |
||||
} |
||||
|
||||
/** |
||||
* 提交表单 |
||||
*/ |
||||
submitEditAccountForm() { |
||||
if (this.editAccountForm.valid) { |
||||
this.sysAccountService.editUser(this.editAccountForm.value, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryData(); |
||||
|
||||
this.message.create('success', '操作成功'); |
||||
|
||||
// 关闭弹窗
|
||||
this.closeEditAccount(); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} else { |
||||
Object.values(this.editAccountForm.controls).forEach(control => { |
||||
if (control.invalid) { |
||||
control.markAsDirty(); |
||||
control.updateValueAndValidity({ onlySelf: true }); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 关闭编辑账户模态框 |
||||
*/ |
||||
closeEditAccount() { |
||||
this.editAccountForm.reset(); |
||||
this.editAccountVisible = false; |
||||
} |
||||
|
||||
/** |
||||
* 打开禁用账户确认框 |
||||
*/ |
||||
showRestore(dataId: number) { |
||||
this.modal.confirm({ |
||||
nzTitle: '提示', |
||||
nzContent: '确定恢复账户状态?', |
||||
nzOnOk: () => this.restore(dataId) |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 恢复 |
||||
*/ |
||||
restore(dataId: number) { |
||||
const param = { |
||||
userId: dataId |
||||
} |
||||
this.sysAccountService.restore(param, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryData(); |
||||
this.message.success("操作成功"); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 打开禁用账户确认框 |
||||
*/ |
||||
showDisable(dataId: number) { |
||||
this.modal.confirm({ |
||||
nzTitle: '提示', |
||||
nzContent: '确定禁用账户吗?禁用后无法登录!', |
||||
nzOnOk: () => this.disable(dataId) |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 禁用 |
||||
*/ |
||||
disable(dataId: number) { |
||||
const param = { |
||||
userId: dataId |
||||
} |
||||
this.sysAccountService.disable(param, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryData(); |
||||
this.message.success("操作成功"); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 打开密码重置确认框 |
||||
*/ |
||||
showResetPwd(dataId: number) { |
||||
this.modal.confirm({ |
||||
nzTitle: '提示', |
||||
nzContent: '确定重置账户登录密码吗?', |
||||
nzOnOk: () => this.resetPwd(dataId) |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 密码重置 |
||||
*/ |
||||
resetPwd(dataId: number) { |
||||
const param = { |
||||
userId: dataId |
||||
} |
||||
this.sysAccountService.resetPwd(param, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryData(); |
||||
this.modal.success({ |
||||
nzTitle: '提示', |
||||
nzContent: '密码重置成功,新密码:123456' |
||||
}); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 展示删除数据 |
||||
*/ |
||||
showDelData(dataId: number) { |
||||
this.modal.confirm({ |
||||
nzTitle: '提示', |
||||
nzContent: '确定删除该账户数据?', |
||||
nzOnOk: () => this.delData(dataId) |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 删除数据 |
||||
*/ |
||||
delData(dataId: number) { |
||||
const param = { |
||||
userId: dataId |
||||
} |
||||
this.sysAccountService.delete(param, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryData(); |
||||
this.message.create('success', '操作成功'); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,100 @@ |
||||
<form nz-form [formGroup]="searchForm" [nzLayout]="'vertical'"> |
||||
<div nz-row [nzGutter]="24"> |
||||
<div nz-col [nzSpan]="4"> |
||||
<nz-form-item> |
||||
<nz-form-label>角色名称</nz-form-label> |
||||
<nz-form-control> |
||||
<input nzSize="large" nz-input formControlName="roleName" placeholder="请输入" /> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</div> |
||||
<div nz-col [nzSpan]="6" class="search-area"> |
||||
<button nz-button [nzType]="'primary'" (click)="searchFormSubmit()">查询</button> |
||||
<button nz-button (click)="searchFormReset()">重置</button> |
||||
<button nz-button [nzType]="'primary'" (click)="showEditRole(true, null)">创建</button> |
||||
</div> |
||||
</div> |
||||
</form> |
||||
|
||||
<nz-table #basicTable |
||||
[nzBordered]="true" |
||||
[nzFrontPagination]="false" |
||||
[nzShowQuickJumper]="true" |
||||
[nzShowTotal]="totalTemplate" |
||||
[(nzPageIndex)]="tablePageNum" |
||||
(nzPageIndexChange)="queryData()" |
||||
[nzTotal]="tableData.total" |
||||
[nzData]="tableData.list" > |
||||
<thead> |
||||
<tr> |
||||
<th nzWidth="80px">角色名称</th> |
||||
<th nzWidth="100px">角色描述</th> |
||||
<th nzWidth="50px">创建时间</th> |
||||
<th nzWidth="50px">更新时间</th> |
||||
<th nzWidth="70px">操作</th> |
||||
</tr> |
||||
</thead> |
||||
<tbody> |
||||
<tr *ngFor="let data of basicTable.data"> |
||||
<td>{{data.roleName}}</td> |
||||
<td>{{data.roleDesc}}</td> |
||||
<td>{{data.createTime | date: 'yyyy-MM-dd HH:mm'}}</td> |
||||
<td>{{data.updateTime | date: 'yyyy-MM-dd HH:mm'}}</td> |
||||
<td> |
||||
<a (click)="showEditRole(false, data)">修改</a> |
||||
<nz-divider nzType="vertical"></nz-divider> |
||||
<a (click)="showAssignRoleMenu(data.id)">分配菜单</a> |
||||
<nz-divider nzType="vertical"></nz-divider> |
||||
<a (click)="showDelData(data.id)">删除</a> |
||||
</td> |
||||
</tr> |
||||
</tbody> |
||||
<ng-template #totalTemplate let-total>总计 {{ total }} 条</ng-template> |
||||
</nz-table> |
||||
|
||||
|
||||
<nz-modal [(nzVisible)]="editRoleVisible" nzTitle="{{editRoleTitle}}" [nzFooter]="null" (nzOnCancel)="closeEditRole()"> |
||||
<ng-container *nzModalContent> |
||||
<form nz-form [formGroup]="editRoleForm" (ngSubmit)="submitEditRoleForm()"> |
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>角色名称</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="角色名称填写有误!"> |
||||
<input nzSize="large" nz-input formControlName="roleName"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>角色描述</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="角色描述填写有误!"> |
||||
<input nzSize="large" nz-input formControlName="roleDesc"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<div nz-flex [nzJustify]="'center'"> |
||||
<button nz-button nzType="primary" class="submit-btn">保存</button> |
||||
</div> |
||||
|
||||
</form> |
||||
</ng-container> |
||||
</nz-modal> |
||||
|
||||
|
||||
<nz-modal [(nzVisible)]="assignRoleMenuVisible" nzTitle="角色菜单权限" [nzFooter]="null" (nzOnCancel)="closeAssignRoleMenu()"> |
||||
<ng-container *nzModalContent> |
||||
<nz-tree |
||||
#nzTreeComponent |
||||
*ngIf="menuTree.length" |
||||
[nzData]="menuTree" |
||||
[nzCheckedKeys]="menuTreeCheckedKeys" |
||||
[nzShowLine]="true" |
||||
[nzExpandAll]="true" |
||||
[nzMultiple]="false" |
||||
[nzCheckable]="true" |
||||
nzVirtualHeight="500px" |
||||
></nz-tree> |
||||
<nz-divider nzOrientation="right"></nz-divider> |
||||
<div nz-flex [nzJustify]="'center'"> |
||||
<button nz-button nzType="primary" class="submit-btn" (click)="submitAssignRoleMenu()">保存</button> |
||||
</div> |
||||
</ng-container> |
||||
</nz-modal> |
@ -0,0 +1,12 @@ |
||||
[nz-form-label] { |
||||
overflow: visible; |
||||
} |
||||
button { |
||||
margin-left: 8px; |
||||
} |
||||
.submit-btn { |
||||
width: 150px; |
||||
} |
||||
.search-area { |
||||
margin-top: 30px; |
||||
} |
@ -0,0 +1,293 @@ |
||||
import {Component, ViewChild} from '@angular/core'; |
||||
import { |
||||
NzTableComponent, |
||||
NzTableModule, |
||||
NzTbodyComponent, |
||||
NzTheadComponent, |
||||
NzThMeasureDirective |
||||
} from "ng-zorro-antd/table"; |
||||
import {NzDividerComponent} from "ng-zorro-antd/divider"; |
||||
import {NzFormDirective, NzFormModule} from "ng-zorro-antd/form"; |
||||
import {NzColDirective, NzRowDirective} from "ng-zorro-antd/grid"; |
||||
import { |
||||
FormGroup, |
||||
NonNullableFormBuilder, |
||||
ReactiveFormsModule, Validators, |
||||
} from "@angular/forms"; |
||||
import {NzButtonComponent} from "ng-zorro-antd/button"; |
||||
import {NzIconDirective} from "ng-zorro-antd/icon"; |
||||
import {NzInputDirective} from "ng-zorro-antd/input"; |
||||
import {NzFlexDirective} from "ng-zorro-antd/flex"; |
||||
import {DatePipe, NgForOf, NgIf} from "@angular/common"; |
||||
import {NzModalComponent, NzModalModule, NzModalService} from "ng-zorro-antd/modal"; |
||||
import {NzMessageService} from "ng-zorro-antd/message"; |
||||
import {NzInputNumberComponent} from "ng-zorro-antd/input-number"; |
||||
import {NzOptionComponent, NzSelectComponent} from "ng-zorro-antd/select"; |
||||
import {NzTreeComponent, NzTreeNodeOptions} from "ng-zorro-antd/tree"; |
||||
import {RoleService} from '../../../services/system/role.service'; |
||||
import {MenuService} from '../../../services/system/menu.service'; |
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-sys-role', |
||||
standalone: true, |
||||
imports: [ |
||||
NzTableComponent, |
||||
NzTheadComponent, |
||||
NzDividerComponent, |
||||
NzTbodyComponent, |
||||
NzFormDirective, |
||||
NzRowDirective, |
||||
ReactiveFormsModule, |
||||
NzColDirective, |
||||
NzButtonComponent, |
||||
NzInputDirective, |
||||
NzFormModule, |
||||
NzFlexDirective, |
||||
NgForOf, |
||||
DatePipe, |
||||
NzThMeasureDirective, |
||||
NzModalComponent, |
||||
NzOptionComponent, |
||||
NzSelectComponent, |
||||
NzModalModule, |
||||
NgIf, |
||||
NzTreeComponent, |
||||
NzTableModule |
||||
], |
||||
templateUrl: './sys-role.component.html', |
||||
styleUrl: './sys-role.component.less' |
||||
}) |
||||
export class SysRoleComponent { |
||||
// 表单页数
|
||||
tablePageNum = 1; |
||||
// 表单数据
|
||||
tableData: any = { |
||||
total: 0, |
||||
list: [], |
||||
}; |
||||
// 搜索表单
|
||||
searchForm: FormGroup; |
||||
// 编辑角色弹出框
|
||||
editRoleVisible = false; |
||||
// 编辑角色表单
|
||||
editRoleForm: FormGroup; |
||||
// 编辑角色标题
|
||||
editRoleTitle = ''; |
||||
// 分配角色菜单弹出框
|
||||
assignRoleMenuVisible = false; |
||||
|
||||
// 当前需要分配权限角色
|
||||
currentAssignRoleId: any = null; |
||||
// 菜单树
|
||||
menuTree: NzTreeNodeOptions[] = []; |
||||
// 菜单已勾选数据
|
||||
menuTreeCheckedKeys: any = []; |
||||
|
||||
@ViewChild('nzTreeComponent', { static: false }) nzTreeComponent!: NzTreeComponent; |
||||
|
||||
constructor(private fb: NonNullableFormBuilder, |
||||
private roleService: RoleService, |
||||
private menuService: MenuService, |
||||
private message: NzMessageService, |
||||
private modal: NzModalService) { |
||||
// 初始化搜索框
|
||||
this.searchForm = this.fb.group({ |
||||
roleName: [''], |
||||
}); |
||||
|
||||
// 初始化表单
|
||||
this.editRoleForm = this.fb.group({ |
||||
id: [''], |
||||
roleName: ['', [Validators.required]], |
||||
roleDesc: [''], |
||||
}); |
||||
|
||||
this.menuService.queryMenuTree((data: any) => { |
||||
console.log("树数据" , data['return_data']); |
||||
this.menuTree = data['return_data']; |
||||
}); |
||||
|
||||
this.queryData(); |
||||
} |
||||
|
||||
/** |
||||
* 获取数据 |
||||
*/ |
||||
queryData() { |
||||
this.searchForm.value.pageNum = this.tablePageNum; |
||||
this.searchForm.value.pageSize = 10; |
||||
this.searchForm.value.time = new Date().getTime(); |
||||
this.roleService.queryList(this.searchForm.value, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
this.tableData = data['return_data']; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 搜索表单提交 |
||||
*/ |
||||
searchFormSubmit(): void { |
||||
this.tablePageNum = 1; |
||||
this.queryData(); |
||||
} |
||||
|
||||
/** |
||||
* 搜索表单重置 |
||||
*/ |
||||
searchFormReset(): void { |
||||
this.searchForm.reset(); |
||||
} |
||||
|
||||
/** |
||||
* 打开编辑角色模态框 |
||||
* @param edit 编辑状态 ture:新增 false:修改 |
||||
* @param data 数据 |
||||
*/ |
||||
showEditRole(edit: boolean, data: any) { |
||||
if (edit) { |
||||
this.editRoleTitle = '创建角色'; |
||||
} else { |
||||
this.editRoleTitle = '修改角色'; |
||||
this.editRoleForm.patchValue(data); |
||||
} |
||||
this.editRoleVisible = true; |
||||
} |
||||
|
||||
/** |
||||
* 打开编辑角色模态框 |
||||
* @param edit |
||||
*/ |
||||
submitEditRoleForm() { |
||||
if (this.editRoleForm.valid) { |
||||
this.roleService.editRole(this.editRoleForm.value, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryData(); |
||||
|
||||
this.message.create('success', '操作成功'); |
||||
|
||||
// 关闭弹窗
|
||||
this.closeEditRole(); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} else { |
||||
Object.values(this.editRoleForm.controls).forEach(control => { |
||||
if (control.invalid) { |
||||
control.markAsDirty(); |
||||
control.updateValueAndValidity({ onlySelf: true }); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 关闭编辑角色模态框 |
||||
*/ |
||||
closeEditRole() { |
||||
this.editRoleForm.reset(); |
||||
this.editRoleVisible = false; |
||||
} |
||||
|
||||
/** |
||||
* 展示删除数据 |
||||
*/ |
||||
showDelData(dataId: number) { |
||||
this.modal.confirm({ |
||||
nzTitle: '提示', |
||||
nzContent: '确定删除数据?', |
||||
nzOnOk: () => this.delData(dataId) |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 删除数据 |
||||
*/ |
||||
delData(dataId: number) { |
||||
const param = { |
||||
id: dataId |
||||
} |
||||
this.roleService.delRole(param, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryData(); |
||||
this.message.create('success', '操作成功'); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 打开分配角色菜单模态框 |
||||
* @param roleId |
||||
*/ |
||||
showAssignRoleMenu(roleId: number) { |
||||
this.currentAssignRoleId = roleId; |
||||
this.menuService.queryRoleMenuArray(roleId, (data: any) => { |
||||
console.log("角色权限菜单" , data['return_data']); |
||||
console.log("树" , this.menuTree); |
||||
this.menuTreeCheckedKeys = data['return_data']; |
||||
}); |
||||
this.assignRoleMenuVisible = true; |
||||
} |
||||
|
||||
/** |
||||
* 菜单递归 |
||||
* @param data |
||||
* @param merIds |
||||
*/ |
||||
recursionData(data: any, merIds: any): any { |
||||
for (let node of data.children) { |
||||
merIds.push(node.key) |
||||
if (node.children != null) { |
||||
this.recursionData(node,merIds); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 提交分配角色菜单权限 |
||||
*/ |
||||
submitAssignRoleMenu() { |
||||
let menuIds: any = []; |
||||
// 已勾选的菜单
|
||||
const checkedNodeList = this.nzTreeComponent.getCheckedNodeList(); |
||||
for (let node of checkedNodeList) { |
||||
menuIds.push(node.origin.key); |
||||
if (node.origin.children != null) { |
||||
menuIds.concat(this.recursionData(node.origin, menuIds)) |
||||
} |
||||
}; |
||||
|
||||
// 半选状态的菜单
|
||||
const halfCheckedNodeList = this.nzTreeComponent.getHalfCheckedNodeList(); |
||||
for (let node of halfCheckedNodeList) { |
||||
menuIds.push(node.key); |
||||
} |
||||
|
||||
const param= { |
||||
roleId: this.currentAssignRoleId, |
||||
menuIds: menuIds |
||||
}; |
||||
this.menuService.assignMenu(param, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
this.message.create('success', '操作成功'); |
||||
this.closeAssignRoleMenu(); |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 关闭分配角色菜单模态框 |
||||
*/ |
||||
closeAssignRoleMenu() { |
||||
this.menuTreeCheckedKeys = []; |
||||
this.assignRoleMenuVisible = false; |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { CommonModule } from '@angular/common'; |
||||
|
||||
@NgModule({ |
||||
declarations: [], |
||||
imports: [ |
||||
CommonModule |
||||
] |
||||
}) |
||||
export class BodyModule { } |
@ -0,0 +1,68 @@ |
||||
<nz-layout> |
||||
<!-- start 头部 start--> |
||||
<nz-header> |
||||
<div nz-row> |
||||
<!-- logo --> |
||||
<div class="logo" nz-col nzSpan="4"> |
||||
<h2>超冠体育管理平台</h2> |
||||
</div> |
||||
<!-- logo --> |
||||
|
||||
<div class="menu" nz-col nzSpan="16"> |
||||
<ul> |
||||
<li *ngFor="let item of menuData" [ngClass]="{'li-selected' : item.selected}" (click)="isSelected(item)">{{item.menuName}}</li> |
||||
</ul> |
||||
</div> |
||||
<div class="user" nz-col nzSpan="4"> |
||||
|
||||
<div> |
||||
<span nz-dropdown [nzDropdownMenu]="menu">{{userInfo['userName']}}</span> |
||||
|
||||
<nz-dropdown-menu #menu="nzDropdownMenu"> |
||||
<ul nz-menu nzSelectable> |
||||
<li nz-menu-item (click)="loginOut()">退出登录</li> |
||||
</ul> |
||||
</nz-dropdown-menu> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</nz-header> |
||||
<!-- end 头部 end --> |
||||
<nz-layout> |
||||
<!-- start 侧边 start--> |
||||
<nz-sider nzCollapsible [(nzCollapsed)]="isCollapse" [nzTrigger]="null" [nzCollapsedWidth]="0" > |
||||
<div class="side_menu" style="height: 50px;"> |
||||
<span |
||||
class="trigger" |
||||
nz-icon |
||||
[nzType]="isCollapse ? 'menu-unfold' : 'menu-fold'" |
||||
(click)="isCollapse = !isCollapse" |
||||
></span> |
||||
</div> |
||||
<!-- start 菜单内容 end--> |
||||
<div> |
||||
<ul nz-menu nzMode="inline"> |
||||
<li nz-submenu nzOpen *ngFor="let item of leftMenuData" nzTitle="{{item.menuName}}" nzIcon="{{item.menuUrlImg}}" > |
||||
<ul> |
||||
<li nz-menu-item nzMatchRouter *ngFor="let childMenu of item['childMenuList']"> |
||||
<a [routerLink]="[currentParentMenu['menuUrl'], childMenu['menuUrl']]" [queryParams]="{title: childMenu['menuName']}">{{childMenu['menuName']}}</a> |
||||
</li> |
||||
</ul> |
||||
</li> |
||||
</ul> |
||||
</div> |
||||
|
||||
|
||||
|
||||
<!-- start 菜单内容 end --> |
||||
</nz-sider> |
||||
<!-- end 侧边 end --> |
||||
<!-- start 主体 start--> |
||||
<nz-content> |
||||
<app-tab></app-tab> |
||||
</nz-content> |
||||
<!-- end 主体 end --> |
||||
</nz-layout> |
||||
</nz-layout> |
||||
|
||||
|
@ -0,0 +1,96 @@ |
||||
nz-header { |
||||
background: #181f47; |
||||
padding: 0 26px; |
||||
.logo { |
||||
h2 { |
||||
color: white; |
||||
} |
||||
} |
||||
.menu { |
||||
width: 52%; |
||||
display: flex; |
||||
justify-content: center; |
||||
|
||||
ul { |
||||
li { |
||||
height: 56px; |
||||
float: left; |
||||
color: #fff; |
||||
opacity: .65; |
||||
font-size: 14px; |
||||
padding: 0 20px; |
||||
cursor: pointer; |
||||
} |
||||
.li-selected { |
||||
opacity: 1; |
||||
border-bottom: 2px solid #1890ff; |
||||
} |
||||
li:hover { |
||||
opacity: 1; |
||||
border-bottom: 2px solid #1890ff; |
||||
} |
||||
list-style-type: none; /* 移除列表的标记,如果需要的话 */ |
||||
padding: 0; /* 移除padding,如果需要的话 */ |
||||
} |
||||
} |
||||
} |
||||
|
||||
nz-sider { |
||||
background: #fff; |
||||
box-shadow: 2px 0 8px rgba(0,0,0,.15); |
||||
height: calc(100vh - 64px);; |
||||
|
||||
.trigger { |
||||
margin-top: 16px; |
||||
font-size: 18px; |
||||
line-height: 50px; |
||||
padding: 0 24px; |
||||
cursor: pointer; |
||||
transition: color 0.3s; |
||||
} |
||||
|
||||
.trigger:hover { |
||||
color: #1890ff; |
||||
} |
||||
} |
||||
nz-content { |
||||
padding: 0 0 0 4px; |
||||
} |
||||
.user { |
||||
div { |
||||
cursor: pointer; |
||||
float: right; |
||||
margin-right: 30px; |
||||
color: white; |
||||
white-space: nowrap; |
||||
text-align: left; |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
} |
||||
|
||||
} |
||||
.file-downLoad { |
||||
width: 300px; |
||||
} |
||||
.button-up { |
||||
font-size: 16px; |
||||
padding: 10px; |
||||
top: 48px; |
||||
left: 22px; |
||||
z-index: 999; |
||||
border-radius: 5px; |
||||
position:absolute; |
||||
height: 80px; |
||||
width: 280px; |
||||
background-color: rgba(0, 0, 0, 0.7); |
||||
} |
||||
.to_top { |
||||
z-index: 999; |
||||
top: 40px; |
||||
position:absolute; |
||||
width: 0; |
||||
height: 0; |
||||
border-bottom: 8px solid rgba(0, 0, 0, 0.7); |
||||
border-left: 8px solid transparent; |
||||
border-right: 8px solid transparent; |
||||
} |
@ -0,0 +1,116 @@ |
||||
|
||||
import { |
||||
AbstractControl, FormControl, |
||||
FormGroup, |
||||
NonNullableFormBuilder, ReactiveFormsModule, |
||||
ValidatorFn, |
||||
Validators |
||||
} from "@angular/forms"; |
||||
import {Component, inject} from '@angular/core'; |
||||
import {DATA, INIT_FLAG, LOGIN_DATA, USER_TOKEN} from '../../../data/login/localStorage.namespace'; |
||||
import {LoginService} from '../../../services/login.service'; |
||||
import {NzConfigService} from 'ng-zorro-antd/core/config'; |
||||
import {LocalStorageService} from '../../../utils/localStorage.service'; |
||||
import {Router, RouterLink} from '@angular/router'; |
||||
import {NzMessageService} from 'ng-zorro-antd/message'; |
||||
import {NzContentComponent, NzHeaderComponent, NzLayoutComponent, NzSiderComponent} from 'ng-zorro-antd/layout'; |
||||
import {NzColDirective, NzRowDirective} from 'ng-zorro-antd/grid'; |
||||
import {NgClass, NgForOf} from '@angular/common'; |
||||
import {NzDropDownDirective, NzDropdownMenuComponent} from 'ng-zorro-antd/dropdown'; |
||||
import {NzMenuDirective, NzMenuItemComponent, NzSubMenuComponent} from 'ng-zorro-antd/menu'; |
||||
import {NzIconDirective} from 'ng-zorro-antd/icon'; |
||||
import {TabComponent} from '../tab/tab.component'; |
||||
|
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-index', |
||||
standalone: true, |
||||
imports: [ |
||||
NzLayoutComponent, |
||||
NzHeaderComponent, |
||||
NzRowDirective, |
||||
NzColDirective, |
||||
NgClass, |
||||
NgForOf, |
||||
NzDropDownDirective, |
||||
NzMenuDirective, |
||||
NzSiderComponent, |
||||
NzIconDirective, |
||||
NzSubMenuComponent, |
||||
NzMenuItemComponent, |
||||
RouterLink, |
||||
NzContentComponent, |
||||
TabComponent, |
||||
NzDropdownMenuComponent |
||||
|
||||
|
||||
], |
||||
templateUrl: './index.component.html', |
||||
styleUrl: './index.component.scss' |
||||
}) |
||||
export class IndexComponent { |
||||
// 菜单数据
|
||||
menuData: any = [{ |
||||
'menuName' : '首页', |
||||
'selected' : true, |
||||
}]; |
||||
userInfo: any; |
||||
// 左侧菜单栏数据
|
||||
leftMenuData: any = []; |
||||
// 侧边菜单展示开关
|
||||
isCollapse = true; |
||||
|
||||
// 当前顶级菜单
|
||||
currentParentMenu: any = {}; |
||||
private login = inject(LoginService); |
||||
|
||||
constructor( |
||||
private message: NzMessageService , |
||||
private storage: LocalStorageService , |
||||
private router: Router, // 路由
|
||||
) { |
||||
|
||||
// @ts-ignore
|
||||
this.menuData = this.menuData.concat(this.storage.getItem(DATA)['menuTree']); |
||||
// @ts-ignore
|
||||
this.userInfo = this.storage.getItem(DATA)['account']; |
||||
} |
||||
|
||||
|
||||
// 选择操作
|
||||
isSelected(item: any) { |
||||
this.menuData.map((data: any) => { |
||||
data.selected = data.menuName === item.menuName; |
||||
}); |
||||
if (item.menuName === '首页') { |
||||
// 激活首页路由
|
||||
this.router.navigateByUrl('/admin/index').finally(); |
||||
} |
||||
|
||||
this.currentParentMenu = item; |
||||
this.leftMenuData = item['childMenuList']; |
||||
this.isCollapse = item['menuName'] === '首页'; |
||||
|
||||
} |
||||
|
||||
// 退出登录
|
||||
public loginOut(): void { |
||||
this.login.loginOut( (data: any) => { |
||||
if (data['return_code'] === '000000') { |
||||
this.storage.removeItem(LOGIN_DATA); |
||||
this.storage.removeItem(DATA); |
||||
this.storage.removeItem(USER_TOKEN); |
||||
this.storage.removeItem(INIT_FLAG); |
||||
location.reload(); |
||||
|
||||
this.router.navigateByUrl('/login').then(); |
||||
} else { |
||||
this.message.error(data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,9 @@ |
||||
|
||||
|
||||
<nz-tabset [(nzSelectedIndex)]="activatedMenuIndex" nzType="editable-card" nzHideAdd (nzClose)="closeTab($event)"> |
||||
<nz-tab *ngFor="let tab of tabs; let i = index" [nzClosable]="i > 0" (nzSelect)="toggleTab(tab.path)" [nzTitle]="tab.title"></nz-tab> |
||||
</nz-tabset> |
||||
<nz-card [nzBordered]="false" [nzBodyStyle]="{ padding: '12px'}"> |
||||
<router-outlet></router-outlet> |
||||
</nz-card> |
||||
|
@ -0,0 +1,34 @@ |
||||
:host { |
||||
background: white; |
||||
overflow: hidden; |
||||
display: block; |
||||
height: 100%; |
||||
} |
||||
|
||||
.card-container ::ng-deep p { |
||||
margin: 0; |
||||
} |
||||
.card-container ::ng-deep > .ant-tabs-card .ant-tabs-content { |
||||
|
||||
margin-top: -16px; |
||||
} |
||||
.card-container ::ng-deep > .ant-tabs-card .ant-tabs-content > .ant-tabs-tabpane { |
||||
background: #f5f5f5; |
||||
padding: 16px; |
||||
} |
||||
.card-container ::ng-deep > .ant-tabs-card > .ant-tabs-nav::before { |
||||
display: none; |
||||
} |
||||
.card-container ::ng-deep > .ant-tabs-card .ant-tabs-tab { |
||||
border-color: transparent; |
||||
background: transparent; |
||||
} |
||||
.card-container ::ng-deep > .ant-tabs-card .ant-tabs-tab-active { |
||||
border-color: #f5f5f5; |
||||
background: #f5f5f5; |
||||
} |
||||
|
||||
nz-card { |
||||
height: calc(98vh - 114px); |
||||
overflow: auto; |
||||
} |
@ -0,0 +1,119 @@ |
||||
import { Component } from '@angular/core'; |
||||
|
||||
import {ActivationEnd, Router, RouterOutlet} from "@angular/router"; |
||||
import {filter} from "rxjs"; |
||||
import {NzTabComponent, NzTabSetComponent} from 'ng-zorro-antd/tabs'; |
||||
import {NzCardComponent} from 'ng-zorro-antd/card'; |
||||
import {NgForOf} from '@angular/common'; |
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-tab', |
||||
standalone: true, |
||||
imports: [ |
||||
NzTabSetComponent, |
||||
NzTabComponent, |
||||
NzCardComponent, |
||||
RouterOutlet, |
||||
NgForOf |
||||
|
||||
], |
||||
templateUrl: './tab.component.html', |
||||
styleUrl: './tab.component.scss' |
||||
}) |
||||
export class TabComponent { |
||||
// 当前打开的Tab页
|
||||
activatedMenuIndex = -1; |
||||
// 存放已打开的Tab页信息
|
||||
tabs: { path: string, title: string }[] = [{ path: '/admin/index', title: '首页' }]; |
||||
constructor(private router: Router) { |
||||
// 激活首页路由
|
||||
this.router.navigateByUrl('/admin/index').finally(); |
||||
|
||||
// 监听路由事件,只订阅 ActivationEnd 事件
|
||||
this.router.events.pipe(filter(e => e instanceof ActivationEnd)) |
||||
.subscribe((e) => { |
||||
const thisEvt = <ActivationEnd>e; |
||||
if (thisEvt.snapshot.routeConfig?.loadChildren) { |
||||
// 当前激活的路由
|
||||
// const activatedRoutePath = thisEvt.snapshot.routeConfig?.path;
|
||||
const activatedRoutePath = this.router.url; |
||||
const routeData = thisEvt.snapshot.queryParams; |
||||
let menuTitle = '新标签页'; |
||||
if(routeData) { |
||||
menuTitle = routeData['title']; |
||||
} |
||||
|
||||
// 该路由是否已激活,激活过则直接打开
|
||||
let isExist = false; |
||||
this.tabs.every((t, i) => { |
||||
if(activatedRoutePath === t.path) { |
||||
this.activatedMenuIndex = i; |
||||
isExist = true; |
||||
return false; |
||||
} |
||||
return true; |
||||
}); |
||||
|
||||
// 指定路由不在tabs中存在(未激活或激活后关闭)
|
||||
if(!isExist) { |
||||
this.activeMenu(activatedRoutePath, menuTitle); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
// 点击菜单激活指定路由并保存tab页签
|
||||
activeMenu(menuPath: string | undefined, menuTitle: string): void { |
||||
if(!menuPath) return; |
||||
let menuIndex = -1; |
||||
this.tabs.every((t, i) => { |
||||
if(menuPath === t.path) { |
||||
menuIndex = i; |
||||
return false; |
||||
} |
||||
return true; |
||||
}); |
||||
|
||||
if(menuIndex === -1) { |
||||
this.tabs.push({path: menuPath, title: menuTitle}); |
||||
menuIndex = this.tabs.length - 1; |
||||
this.activatedMenuIndex = menuIndex; |
||||
} |
||||
} |
||||
// 激活路由
|
||||
activeRoute(path: string): void { |
||||
this.router.navigateByUrl(path).finally(); |
||||
} |
||||
|
||||
// 切换tab,激活对应路由
|
||||
toggleTab(path: string): void { |
||||
this.activeRoute(path); |
||||
} |
||||
|
||||
// tab页签关闭,从缓存中删除对应信息
|
||||
closeTab(tabsObj: any): void { |
||||
if (1 === this.tabs.length) return; |
||||
const path = this.tabs[tabsObj['index']]['path']; |
||||
|
||||
let selectedIndex = -1; |
||||
this.tabs.every((t, i) => { |
||||
if(t.path === path) { |
||||
selectedIndex = i; |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
}); |
||||
this.tabs.splice(selectedIndex, 1); |
||||
|
||||
if(selectedIndex === this.activatedMenuIndex) { |
||||
let prevIndex = this.activatedMenuIndex - 1; |
||||
this.activatedMenuIndex = prevIndex > 0 ? prevIndex : 0; |
||||
this.activeRoute(this.tabs[this.activatedMenuIndex].path); |
||||
}else if (this.activatedMenuIndex > selectedIndex) { |
||||
this.activatedMenuIndex -= 1; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { CommonModule } from '@angular/common'; |
||||
|
||||
|
||||
|
||||
@NgModule({ |
||||
declarations: [], |
||||
imports: [ |
||||
CommonModule |
||||
] |
||||
}) |
||||
export class ErrorModule { } |
@ -0,0 +1,15 @@ |
||||
import { Routes } from '@angular/router'; |
||||
import {Error403Component} from "./error403/error403.component"; |
||||
import {Error404Component} from "./error404/error404.component"; |
||||
import {Error500Component} from "./error500/error500.component"; |
||||
import {Error401Component} from "./error401/error401.component"; |
||||
|
||||
|
||||
|
||||
export const ERROR_ROUTES: Routes = [ |
||||
|
||||
{ path: '401', component: Error401Component }, |
||||
{ path: '403', component: Error403Component }, |
||||
{ path: '404', component: Error404Component }, |
||||
{ path: '500', component: Error500Component }, |
||||
]; |
@ -0,0 +1,5 @@ |
||||
<nz-result nzStatus="warning" nzTitle="当前登录信息已过期,请重新登录!"> |
||||
<div nz-result-extra> |
||||
<button nz-button nzType="primary" (click)="loginOut()">重新登录</button> |
||||
</div> |
||||
</nz-result> |
@ -0,0 +1,45 @@ |
||||
import { Component } from '@angular/core'; |
||||
import {NzResultModule} from "ng-zorro-antd/result"; |
||||
import {NzButtonComponent} from "ng-zorro-antd/button"; |
||||
import {NzMessageService} from "ng-zorro-antd/message"; |
||||
import {Router} from "@angular/router"; |
||||
import {DATA, INIT_FLAG, LOGIN_DATA, USER_TOKEN} from "../../../data/login/localStorage.namespace"; |
||||
import {LocalStorageService} from '../../../utils/localStorage.service'; |
||||
import {LoginService} from '../../../services/login.service'; |
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-error401', |
||||
standalone: true, |
||||
imports: [ |
||||
NzResultModule, |
||||
NzButtonComponent |
||||
], |
||||
templateUrl: './error401.component.html', |
||||
styleUrl: './error401.component.less' |
||||
}) |
||||
export class Error401Component { |
||||
constructor( |
||||
private storage: LocalStorageService, |
||||
private message: NzMessageService, |
||||
private router: Router, // 路由
|
||||
private login: LoginService |
||||
) {} |
||||
|
||||
|
||||
// 退出登录
|
||||
public loginOut(): void { |
||||
this.login.loginOut( (data: any) => { |
||||
if (data['return_code'] === '000000') { |
||||
this.storage.removeItem(LOGIN_DATA); |
||||
this.storage.removeItem(DATA); |
||||
this.storage.removeItem(USER_TOKEN); |
||||
this.storage.removeItem(INIT_FLAG); |
||||
this.router.navigate(['/login']).then(r => console.log(r)); |
||||
|
||||
} else { |
||||
this.message.error(data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
<nz-result nzStatus="403" nzTitle="403" nzSubTitle="抱歉,您无权访问此页面。"> |
||||
<div nz-result-extra> |
||||
<button nz-button nzType="primary" (click)="getHome()">返回首页</button> |
||||
</div> |
||||
</nz-result> |
@ -0,0 +1,29 @@ |
||||
import { Component } from '@angular/core'; |
||||
import {NzResultModule} from "ng-zorro-antd/result"; |
||||
import {NzButtonComponent} from "ng-zorro-antd/button"; |
||||
|
||||
import {Router} from "@angular/router"; |
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-error403', |
||||
standalone: true, |
||||
imports: [ |
||||
NzResultModule, |
||||
NzButtonComponent |
||||
], |
||||
templateUrl: './error403.component.html', |
||||
styleUrl: './error403.component.less' |
||||
}) |
||||
export class Error403Component { |
||||
constructor( |
||||
|
||||
private router: Router, // 路由
|
||||
) {} |
||||
|
||||
|
||||
// 退出登录
|
||||
public getHome(): void { |
||||
this.router.navigateByUrl('/admin/index').then(r => console.log("返回内容" ,r)); |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
<nz-result nzStatus="404" nzTitle="404" nzSubTitle="很抱歉,您访问的页面不存在。"> |
||||
<div nz-result-extra> |
||||
<button nz-button nzType="primary" (click)="getHome()">返回首页</button> |
||||
</div> |
||||
</nz-result> |
@ -0,0 +1,27 @@ |
||||
import { Component } from '@angular/core'; |
||||
import {Router} from "@angular/router"; |
||||
import {NzResultModule} from "ng-zorro-antd/result"; |
||||
import {NzButtonComponent} from "ng-zorro-antd/button"; |
||||
|
||||
@Component({ |
||||
selector: 'app-error404', |
||||
standalone: true, |
||||
imports: [ |
||||
NzResultModule, |
||||
NzButtonComponent |
||||
], |
||||
templateUrl: './error404.component.html', |
||||
styleUrl: './error404.component.less' |
||||
}) |
||||
export class Error404Component { |
||||
constructor( |
||||
|
||||
private router: Router, // 路由
|
||||
) {} |
||||
|
||||
|
||||
// 退出登录
|
||||
public getHome(): void { |
||||
this.router.navigateByUrl('/admin/index').then(r => console.log("返回内容" ,r)); |
||||
} |
||||
} |
@ -0,0 +1,5 @@ |
||||
<nz-result nzStatus="500" nzTitle="500" nzSubTitle="很抱歉,服务器上出现错误。"> |
||||
<div nz-result-extra> |
||||
<button nz-button nzType="primary" (click)="getHome()">返回首页</button> |
||||
</div> |
||||
</nz-result> |
@ -0,0 +1,27 @@ |
||||
import { Component } from '@angular/core'; |
||||
import {NzResultModule} from "ng-zorro-antd/result"; |
||||
import {NzButtonComponent} from "ng-zorro-antd/button"; |
||||
import {Router} from "@angular/router"; |
||||
|
||||
@Component({ |
||||
selector: 'app-error500', |
||||
standalone: true, |
||||
imports: [ |
||||
NzResultModule, |
||||
NzButtonComponent |
||||
], |
||||
templateUrl: './error500.component.html', |
||||
styleUrl: './error500.component.less' |
||||
}) |
||||
export class Error500Component { |
||||
constructor( |
||||
|
||||
private router: Router, // 路由
|
||||
) {} |
||||
|
||||
|
||||
// 退出登录
|
||||
public getHome(): void { |
||||
this.router.navigateByUrl('/admin/index').then(r => console.log("返回内容" ,r)); |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { CommonModule } from '@angular/common'; |
||||
|
||||
|
||||
|
||||
@NgModule({ |
||||
declarations: [], |
||||
imports: [ |
||||
CommonModule |
||||
] |
||||
}) |
||||
export class IndexModule { } |
@ -0,0 +1,6 @@ |
||||
import { Routes } from '@angular/router'; |
||||
import {IndexComponent} from "./index/index.component"; |
||||
|
||||
export const INDEX_ROUTES: Routes = [ |
||||
{ path: '', component: IndexComponent} |
||||
]; |
@ -0,0 +1,13 @@ |
||||
import { Component } from '@angular/core'; |
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-index', |
||||
imports: [], |
||||
templateUrl: './index.component.html', |
||||
standalone: true, |
||||
styleUrl: './index.component.scss' |
||||
}) |
||||
export class IndexComponent { |
||||
isCollapsed = false; |
||||
} |
@ -0,0 +1,10 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { CommonModule } from '@angular/common'; |
||||
|
||||
@NgModule({ |
||||
declarations: [], |
||||
imports: [ |
||||
CommonModule, |
||||
] |
||||
}) |
||||
export class LoginModule { } |
@ -0,0 +1,6 @@ |
||||
import { Routes } from '@angular/router'; |
||||
import {LoginComponent} from "./login/login.component"; |
||||
|
||||
export const LOGIN_ROUTES: Routes = [ |
||||
{ path: '', component: LoginComponent} |
||||
]; |
@ -0,0 +1,78 @@ |
||||
<div class="bg"> |
||||
<!-- 登录框--> |
||||
<div class="login-box"> |
||||
<!-- 广告位--> |
||||
<div class="login-box-size box-left"> |
||||
<nz-carousel [nzAutoPlay] = true [nzDots] = false [nzEffect]="'effect'"> |
||||
<div nz-carousel-content *ngFor="let index of backgroundImage"> |
||||
<img ngSrc="{{index}}" alt="" priority={true} fill=""> |
||||
</div> |
||||
</nz-carousel> |
||||
</div> |
||||
<!-- 登录--> |
||||
<div class="login-box-size box-center"> |
||||
<h1>超冠体育 后台登录</h1> |
||||
<div> |
||||
<form nz-form [formGroup]="validateForm" class="login-form" (ngSubmit)="submitForm()"> |
||||
<nz-form-item> |
||||
<nz-form-control nzErrorTip="请输入您的用户名!"> |
||||
<nz-input-group nzPrefixIcon="user"> |
||||
<input type="text" nz-input formControlName="loginName" nzSize="large" placeholder="用户名" /> |
||||
</nz-input-group> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
<nz-form-item> |
||||
<nz-form-control nzErrorTip="请输入您的密码!"> |
||||
<nz-input-group nzPrefixIcon="lock" [nzSuffix]="suffixTemplate"> |
||||
<input |
||||
[type]="passwordVisible ? 'text' : 'password'" |
||||
nz-input |
||||
nzSize="large" |
||||
placeholder="密码" |
||||
formControlName="password" |
||||
/> |
||||
</nz-input-group> |
||||
<ng-template #suffixTemplate> |
||||
<span |
||||
nz-icon |
||||
[nzType]="passwordVisible ? 'eye-invisible' : 'eye'" |
||||
(click)="passwordVisible = !passwordVisible" |
||||
></span> |
||||
</ng-template> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
<nz-form-item> |
||||
<nz-form-control nzErrorTip="请滑动验证!"> |
||||
<nz-input-group > |
||||
<nz-row> |
||||
<nz-col nzSpan="18"> |
||||
<nz-slider formControlName="slider" [nzDisabled]="false"></nz-slider> |
||||
</nz-col> |
||||
<div nz-col nzSpan="6"> |
||||
请滑动至 |
||||
<span class="take_care">{{randomNumber}}</span> |
||||
</div> |
||||
</nz-row> |
||||
</nz-input-group> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
<div nz-row class="login-form-margin"> |
||||
<div nz-col [nzSpan]="24"> |
||||
<label nz-checkbox formControlName="remember"> |
||||
<span>记住密码</span> |
||||
</label> |
||||
</div> |
||||
|
||||
</div> |
||||
<button nz-button nzSize="large" class="login-form-button login-form-margin" [nzType]="'primary'">登录</button> |
||||
|
||||
</form> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
<!-- 底部 --> |
||||
<div class="footer"> |
||||
渝ICP备19012384号-1 |
||||
</div> |
||||
</div> |
||||
|
@ -0,0 +1,80 @@ |
||||
.bg { |
||||
//背景图 |
||||
width: 100%; |
||||
height: 100%; |
||||
background: linear-gradient(126deg, #0f75ff, #2cd8d4); |
||||
overflow: hidden; |
||||
//登录框 |
||||
.login-box { |
||||
width: 1000px; |
||||
height: 660px; |
||||
background: white; |
||||
margin: 200px auto 0; |
||||
border-radius: 10px; |
||||
//盒子大小 |
||||
.login-box-size { |
||||
width: 50%; |
||||
height: 660px; |
||||
float: left; |
||||
border-radius: 10px; |
||||
//盒子中图片 |
||||
|
||||
[nz-carousel-content] { |
||||
text-align: center; |
||||
height: 660px; |
||||
color: #fff; |
||||
overflow: hidden; |
||||
} |
||||
h1 { |
||||
margin-top: 70px; |
||||
color: #0f75ff; |
||||
font-weight: bold; |
||||
letter-spacing: 4px; |
||||
} |
||||
} |
||||
.box-left { |
||||
background: #f2f5fa; |
||||
} |
||||
.box-center { |
||||
text-align: center; |
||||
} |
||||
|
||||
} |
||||
.footer { |
||||
text-align: center; |
||||
width: 100%; |
||||
height: 50px; |
||||
line-height: 50px; |
||||
position: fixed; |
||||
bottom: 0; |
||||
background: white; |
||||
} |
||||
} |
||||
.login-form { |
||||
margin-top: 50px; |
||||
margin-left: 40px; |
||||
max-width: 400px; |
||||
.take_care { |
||||
color: red; |
||||
font-size: 20px; |
||||
} |
||||
input { |
||||
height: 32px; |
||||
} |
||||
nz-form-control { |
||||
margin-top: 10px; |
||||
} |
||||
} |
||||
|
||||
.login-form-margin { |
||||
margin-bottom: 16px; |
||||
float: right; |
||||
} |
||||
|
||||
.login-form-button { |
||||
margin-top: 20px; |
||||
width: 100%; |
||||
} |
||||
i { |
||||
cursor: pointer; |
||||
} |
@ -0,0 +1,113 @@ |
||||
import {Component, inject} from '@angular/core'; |
||||
import {NzCarouselComponent, NzCarouselContentDirective} from "ng-zorro-antd/carousel"; |
||||
import {NgForOf, NgOptimizedImage} from "@angular/common"; |
||||
import {NzFormControlComponent, NzFormDirective, NzFormItemComponent} from "ng-zorro-antd/form"; |
||||
import { |
||||
NonNullableFormBuilder, |
||||
ReactiveFormsModule, |
||||
Validators |
||||
} from "@angular/forms"; |
||||
import {NzInputDirective, NzInputGroupComponent} from "ng-zorro-antd/input"; |
||||
import {NzColDirective, NzRowDirective} from "ng-zorro-antd/grid"; |
||||
import {NzButtonComponent} from "ng-zorro-antd/button"; |
||||
import {NzCheckboxComponent} from "ng-zorro-antd/checkbox"; |
||||
import {backgroundImage} from "../../../data/login/login.namespace"; |
||||
import {NzSliderComponent} from "ng-zorro-antd/slider"; |
||||
import {MathUtils} from "../../../utils/mathUtils.service"; |
||||
import {NzMessageService} from "ng-zorro-antd/message"; |
||||
import {DATA, INIT_FLAG, LOGIN_DATA, USER_TOKEN} from "../../../data/login/localStorage.namespace"; |
||||
import {Router} from "@angular/router"; |
||||
import { LocalStorageService} from "../../../utils/localStorage.service"; |
||||
import {NzIconDirective} from "ng-zorro-antd/icon"; |
||||
import {LoginService} from '../../../services/login.service'; |
||||
|
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-login', |
||||
standalone: true, |
||||
templateUrl: './login.component.html', |
||||
host: {ngSkipHydration: 'true'}, |
||||
imports: [ |
||||
NzCarouselComponent, |
||||
NzCarouselContentDirective, |
||||
NgOptimizedImage, |
||||
NzFormDirective, |
||||
ReactiveFormsModule, |
||||
NzFormItemComponent, |
||||
NzFormControlComponent, |
||||
NzInputGroupComponent, |
||||
NzInputDirective, |
||||
NzIconDirective, |
||||
NzRowDirective, |
||||
NzColDirective, |
||||
NzSliderComponent, |
||||
NzCheckboxComponent, |
||||
NzButtonComponent, |
||||
NgForOf |
||||
], |
||||
|
||||
styleUrl: './login.component.less' |
||||
}) |
||||
export class LoginComponent { |
||||
|
||||
private fb = inject(NonNullableFormBuilder); |
||||
private login = inject(LoginService); |
||||
constructor( |
||||
private message: NzMessageService , |
||||
private storage: LocalStorageService , |
||||
private router: Router, // 路由
|
||||
) {} |
||||
|
||||
validateForm = this.fb.group({ |
||||
loginName: this.fb.control('', [Validators.required]), |
||||
password: this.fb.control('', [Validators.required]), |
||||
slider: [0, [Validators.required]], |
||||
remember: this.fb.control(true) |
||||
}); |
||||
|
||||
// 背景图片
|
||||
backgroundImage = backgroundImage; |
||||
passwordVisible = false; |
||||
// 验证随机数
|
||||
randomNumber = MathUtils.generateRandomNumber(100); |
||||
|
||||
// 表单
|
||||
|
||||
|
||||
submitForm(): void { |
||||
if (this.validateForm.valid) { |
||||
if (Number(this.validateForm.value.slider) !== this.randomNumber) { |
||||
this.message.warning('验证不通过!') |
||||
this.randomNumber = MathUtils.generateRandomNumber(100) |
||||
return; |
||||
} |
||||
|
||||
// 发起登录
|
||||
this.login.userLogin(this.validateForm.value , (data: any) => { |
||||
if (data['return_code'] === '000000') { |
||||
this.storage.setItem(LOGIN_DATA, this.validateForm.value); |
||||
this.storage.setItem(DATA, data['return_data']['object']); |
||||
this.storage.setItem(USER_TOKEN, data['return_data']['token']); |
||||
this.storage.setItem(INIT_FLAG, true); |
||||
this.router.navigateByUrl('/admin/index'); |
||||
|
||||
} else { |
||||
this.message.error(data['return_msg']); |
||||
} |
||||
}); |
||||
|
||||
this.randomNumber = MathUtils.generateRandomNumber(100) |
||||
console.log('submit', this.validateForm.value); |
||||
} else { |
||||
Object.values(this.validateForm.controls).forEach(control => { |
||||
if (control.invalid) { |
||||
control.markAsDirty(); |
||||
control.updateValueAndValidity({onlySelf: true}); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
} |
||||
} |
@ -0,0 +1,30 @@ |
||||
<form nz-form [formGroup]="validateForm" class="ant-advanced-search-form"> |
||||
<div nz-row [nzGutter]="24"> |
||||
@for (control of controlArray; track control) { |
||||
<div nz-col [nzSpan]="8" [hidden]="!control.show"> |
||||
<nz-form-item> |
||||
<nz-form-label [nzFor]="'field' + control.index">Field {{ control.index }}</nz-form-label> |
||||
<nz-form-control> |
||||
<input |
||||
nz-input |
||||
placeholder="placeholder" |
||||
[formControlName]="'field' + control.index" |
||||
[attr.id]="'field' + control.index" |
||||
/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
</div> |
||||
} |
||||
</div> |
||||
<div nz-row> |
||||
<div nz-col [nzSpan]="24" class="search-area"> |
||||
<button nz-button [nzType]="'primary'">Search</button> |
||||
<button nz-button (click)="resetForm()">Clear</button> |
||||
<a class="collapse" (click)="toggleCollapse()"> |
||||
Collapse |
||||
<nz-icon [nzType]="isCollapse ? 'down' : 'up'" /> |
||||
</a> |
||||
</div> |
||||
</div> |
||||
</form> |
||||
<div class="search-result-list">Search Result List</div> |
@ -0,0 +1,33 @@ |
||||
.ant-advanced-search-form { |
||||
padding: 24px; |
||||
background: #fbfbfb; |
||||
border: 1px solid #d9d9d9; |
||||
border-radius: 6px; |
||||
} |
||||
|
||||
.search-result-list { |
||||
margin-top: 16px; |
||||
border: 1px dashed #e9e9e9; |
||||
border-radius: 6px; |
||||
background-color: #fafafa; |
||||
min-height: 200px; |
||||
text-align: center; |
||||
padding-top: 80px; |
||||
} |
||||
|
||||
[nz-form-label] { |
||||
overflow: visible; |
||||
} |
||||
|
||||
button { |
||||
margin-left: 8px; |
||||
} |
||||
|
||||
.collapse { |
||||
margin-left: 8px; |
||||
font-size: 12px; |
||||
} |
||||
|
||||
.search-area { |
||||
text-align: right; |
||||
} |
@ -0,0 +1,35 @@ |
||||
import {Component, inject} from '@angular/core'; |
||||
import {FormControl, FormRecord, NonNullableFormBuilder, ReactiveFormsModule, Validators} from '@angular/forms'; |
||||
import {NzColDirective, NzRowDirective} from 'ng-zorro-antd/grid'; |
||||
import {NzInputDirective} from 'ng-zorro-antd/input'; |
||||
import {NzFormDirective} from 'ng-zorro-antd/form'; |
||||
import {NzButtonComponent} from 'ng-zorro-antd/button'; |
||||
import {NzIconDirective} from 'ng-zorro-antd/icon'; |
||||
|
||||
@Component({ |
||||
selector: 'app-student-item', |
||||
imports: [ |
||||
ReactiveFormsModule, |
||||
NzRowDirective, |
||||
NzColDirective, |
||||
NzInputDirective, |
||||
NzFormDirective, |
||||
NzButtonComponent |
||||
], |
||||
templateUrl: './student-item.component.html', |
||||
standalone: true, |
||||
styleUrl: './student-item.component.scss' |
||||
}) |
||||
export class StudentItemComponent { |
||||
|
||||
private fb = inject(NonNullableFormBuilder); |
||||
validateForm = this.fb.group({ |
||||
name: this.fb.control('', [Validators.required]), |
||||
}); |
||||
constructor() { } |
||||
|
||||
resetForm(): void { |
||||
this.validateForm.reset(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,12 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { CommonModule } from '@angular/common'; |
||||
|
||||
|
||||
|
||||
@NgModule({ |
||||
declarations: [], |
||||
imports: [ |
||||
CommonModule |
||||
] |
||||
}) |
||||
export class StudentModule { } |
@ -0,0 +1,7 @@ |
||||
import { Routes } from '@angular/router'; |
||||
import {StudentItemComponent} from './student-item/student-item.component'; |
||||
|
||||
|
||||
export const STUDENT_ROUTES: Routes = [ |
||||
{ path: 'student-item', component: StudentItemComponent}, |
||||
]; |
@ -0,0 +1,102 @@ |
||||
<nz-list nzGrid> |
||||
<div nz-row [nzGutter]="16"> |
||||
<div nz-col [nzSpan]="12"> |
||||
<nz-list-item> |
||||
<nz-card [nzTitle]="'系统菜单'"> |
||||
<nz-spin [nzSpinning]="!treeView"></nz-spin> |
||||
<nz-tree |
||||
*ngIf="menuTree.length > 0 && treeView" |
||||
[nzData]="menuTree" |
||||
[nzShowLine]="true" |
||||
[nzExpandAll]="true" |
||||
(nzClick)="clickNode($event)" |
||||
[nzMultiple]="false" |
||||
></nz-tree> |
||||
</nz-card> |
||||
</nz-list-item> |
||||
</div> |
||||
<div nz-col [nzSpan]="12"> |
||||
<nz-list-item> |
||||
<nz-card [nzTitle]="'菜单详情'"> |
||||
<nz-descriptions [nzExtra]="extraTemplate" nzBordered> |
||||
<nz-descriptions-item [nzSpan]="3" nzTitle="父级菜单">{{menuDetail?.parentMenu?menuDetail.parentMenu.menuName:'无'}}</nz-descriptions-item> |
||||
<nz-descriptions-item [nzSpan]="3" nzTitle="菜单名称">{{menuDetail.menuName?menuDetail.menuName:'无'}}</nz-descriptions-item> |
||||
<nz-descriptions-item [nzSpan]="3" nzTitle="菜单类型">{{menuDetail.menuType == 1 ? '菜单' : '按钮'}}</nz-descriptions-item> |
||||
<nz-descriptions-item [nzSpan]="3" nzTitle="菜单URL">{{menuDetail.menuUrl?menuDetail.menuUrl:'无'}}</nz-descriptions-item> |
||||
<nz-descriptions-item [nzSpan]="3" nzTitle="菜单图标">{{menuDetail.menuUrlImg?menuDetail.menuUrlImg:'无'}}</nz-descriptions-item> |
||||
<nz-descriptions-item [nzSpan]="3" nzTitle="菜单描述">{{menuDetail.menuDesc?menuDetail.menuDesc:'无'}}</nz-descriptions-item> |
||||
|
||||
<ng-template #extraTemplate> |
||||
<div nz-row [nzGutter]="12"> |
||||
<div nz-col nzSpan="8"><button nz-button nzType="primary" (click)="openEditMenu(true)">添加</button></div> |
||||
<div nz-col nzSpan="8"><button nz-button nzType="primary" (click)="openEditMenu(false)">修改</button></div> |
||||
<div nz-col nzSpan="8"><button nz-button nzType="primary" (click)="showDelMenu()" nzDanger>删除</button></div> |
||||
</div> |
||||
</ng-template> |
||||
</nz-descriptions> |
||||
</nz-card> |
||||
</nz-list-item> |
||||
</div> |
||||
</div> |
||||
</nz-list> |
||||
|
||||
<nz-modal [(nzVisible)]="isVisible" nzTitle="编辑菜单" (nzOnCancel)="isVisible = false" (nzOnOk)="handleOk()"> |
||||
<ng-container *nzModalContent> |
||||
<form nz-form [formGroup]="validateForm"> |
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzFor="menuPSid">父级菜单</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24"> |
||||
<nz-tree-select |
||||
formControlName="menuPSid" |
||||
[nzNodes]="menuTree" |
||||
nzShowSearch |
||||
></nz-tree-select> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>菜单名称</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="菜单名称填写有误!"> |
||||
<input nz-input formControlName="menuName"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>菜单类型</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="菜单类型选择有误!"> |
||||
<nz-select formControlName="menuType" nzShowSearch> |
||||
<nz-option *ngFor="let item of menuTypeArray" nzValue="{{item.codeValue}}" nzLabel="{{item.codeName}}"></nz-option> |
||||
</nz-select> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>菜单URL</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="菜单URL填写有误!"> |
||||
<input nz-input formControlName="menuUrl"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>菜单顺序</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="菜单顺序填写有误!"> |
||||
<nz-input-number [nzMin]="1" [nzMax]="999" [nzStep]="1" formControlName="menuSort"></nz-input-number> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24">图标URL</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24"> |
||||
<input nz-input formControlName="menuUrlImg"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
<nz-form-item> |
||||
<nz-form-label [nzSm]="6" [nzXs]="24">菜单描述</nz-form-label> |
||||
<nz-form-control [nzSm]="14" [nzXs]="24"> |
||||
<input nz-input formControlName="menuDesc"/> |
||||
</nz-form-control> |
||||
</nz-form-item> |
||||
|
||||
</form> |
||||
</ng-container> |
||||
</nz-modal> |
@ -0,0 +1,206 @@ |
||||
import {Component, inject} from '@angular/core'; |
||||
import {NzListModule} from 'ng-zorro-antd/list'; |
||||
import {NzGridModule} from 'ng-zorro-antd/grid'; |
||||
import {NzCardModule} from 'ng-zorro-antd/card'; |
||||
import {DictionaryService} from '../../../services/commons/dictionary.service'; |
||||
import {MenuService} from '../../../services/system/menu.service'; |
||||
import {NzSpinComponent} from 'ng-zorro-antd/spin'; |
||||
import {NzTreeComponent} from 'ng-zorro-antd/tree'; |
||||
import {NgForOf, NgIf} from '@angular/common'; |
||||
import {NzDescriptionsComponent, NzDescriptionsItemComponent} from 'ng-zorro-antd/descriptions'; |
||||
import {NzButtonComponent} from 'ng-zorro-antd/button'; |
||||
import {NonNullableFormBuilder, ReactiveFormsModule, Validators} from '@angular/forms'; |
||||
import {NzModalComponent, NzModalContentDirective, NzModalModule, NzModalService} from 'ng-zorro-antd/modal'; |
||||
import {NzFormControlComponent, NzFormDirective, NzFormLabelComponent, NzFormModule} from 'ng-zorro-antd/form'; |
||||
import {NzInputDirective} from 'ng-zorro-antd/input'; |
||||
import {NzTreeSelectComponent} from 'ng-zorro-antd/tree-select'; |
||||
import {NzOptionComponent, NzSelectComponent} from 'ng-zorro-antd/select'; |
||||
import {NzInputNumberComponent} from 'ng-zorro-antd/input-number'; |
||||
import {NzMessageService} from 'ng-zorro-antd/message'; |
||||
import {NzNotificationService} from 'ng-zorro-antd/notification'; |
||||
|
||||
|
||||
@Component({ |
||||
selector: 'app-menu', |
||||
imports: [ |
||||
NzCardModule, |
||||
NzGridModule, |
||||
NzFormModule, |
||||
NzModalModule, |
||||
NzListModule, |
||||
NzSpinComponent, |
||||
NzTreeComponent, |
||||
NgIf, |
||||
NzDescriptionsComponent, |
||||
NzDescriptionsItemComponent, NzButtonComponent, NzModalComponent, NzModalContentDirective, NzFormDirective, ReactiveFormsModule, NzInputDirective, NzFormControlComponent, NzFormLabelComponent, NzTreeSelectComponent, NzSelectComponent, NzOptionComponent, NzInputNumberComponent, NgForOf], |
||||
templateUrl: './menu.component.html', |
||||
standalone: true, |
||||
styleUrl: './menu.component.scss' |
||||
}) |
||||
export class MenuComponent { |
||||
|
||||
private fb = inject(NonNullableFormBuilder); |
||||
private readonly notification = inject(NzNotificationService); |
||||
// 菜单类型
|
||||
menuTypeArray: any = []; |
||||
// 菜单数据
|
||||
menuData: any = []; |
||||
// 菜单树形数据
|
||||
menuTree: any[] = []; |
||||
// 菜单详情
|
||||
menuDetail: any = {}; |
||||
// 编辑菜单弹出框
|
||||
isVisible = false; |
||||
// 树视图展示状态
|
||||
treeView= false; |
||||
constructor( |
||||
private dictionary: DictionaryService, |
||||
private modal: NzModalService, |
||||
private message: NzMessageService , |
||||
private menuService: MenuService |
||||
) { |
||||
// 获取菜单类型
|
||||
this.dictionary.getDictionary('MENU_TYPE ', (data: any) => { |
||||
this.menuTypeArray = data['return_data']; |
||||
}); |
||||
this.queryMenuTree(); |
||||
} |
||||
|
||||
validateForm = this.fb.group({ |
||||
menuName: this.fb.control('', [Validators.required]), |
||||
menuType: this.fb.control('', [Validators.required]), |
||||
menuUrl: this.fb.control('', [Validators.required]), |
||||
menuSort: this.fb.control('', [Validators.required]), |
||||
menuPSid: this.fb.control(null), |
||||
menuUrlImg: this.fb.control(''), |
||||
menuDesc: this.fb.control(''), |
||||
id: this.fb.control(null) |
||||
}); |
||||
|
||||
// 获取菜单树数据
|
||||
queryMenuTree() { |
||||
this.menuService.queryMenuTree((data: any) => { |
||||
this.menuTree = data['return_data']; |
||||
this.treeView = true; |
||||
this.queryMenuData(); |
||||
}); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 查询菜单原始数据 |
||||
*/ |
||||
queryMenuData() { |
||||
this.menuService.queryMenuList((data: any) => { |
||||
this.menuData = data['return_data']; |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 点击树节点 |
||||
* @param nodeData |
||||
*/ |
||||
clickNode(nodeData: any) { |
||||
const menuId = nodeData['keys'][0]; |
||||
if (menuId != null) { |
||||
const menuObj = this.menuData.find((o: any) => o.id == menuId); |
||||
if (menuObj != null && menuObj.menuPSid != null) { |
||||
// 获取父级菜单
|
||||
menuObj['parentMenu'] = this.menuData.find((o: any) => o.id == menuObj.menuPSid); |
||||
} |
||||
this.menuDetail = menuObj; |
||||
} |
||||
} |
||||
|
||||
|
||||
// 编辑菜单
|
||||
openEditMenu(isEdit: boolean): void { |
||||
if (isEdit) { |
||||
this.validateForm.reset(); |
||||
const menu:{} = { |
||||
menuPSid: ""+this.menuDetail.id, |
||||
menuType: '1' |
||||
}; |
||||
this.validateForm.patchValue(menu); |
||||
} else { |
||||
// 判断是否点击需要修改菜单
|
||||
if ( this.menuDetail?.id == null) { |
||||
this.notification.create( |
||||
'warning', |
||||
'修改提示', |
||||
'请点击需要修改的菜单!', |
||||
); |
||||
return; |
||||
} |
||||
this.menuDetail.menuPSid = String(this.menuDetail.menuPSid); |
||||
this.menuDetail.menuType = String(this.menuDetail.menuType); |
||||
this.validateForm.patchValue(this.menuDetail); |
||||
} |
||||
this.isVisible = true; |
||||
} |
||||
|
||||
// 提交菜单
|
||||
handleOk(): void { |
||||
if (this.validateForm.valid) { |
||||
this.treeView = false; |
||||
console.log(this.validateForm.controls['menuPSid'].value); |
||||
if (this.validateForm.controls['menuPSid'].value == 'undefined') { |
||||
this.validateForm.controls['menuPSid'].setValue(null); |
||||
} |
||||
console.log(this.validateForm.value); |
||||
this.menuService.editMenu(this.validateForm.value, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryMenuTree(); |
||||
|
||||
this.message.create('success', '操作成功'); |
||||
|
||||
// 关闭弹窗
|
||||
this.isVisible = false; |
||||
} else { |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} else { |
||||
Object.values(this.validateForm.controls).forEach(control => { |
||||
if (control.invalid) { |
||||
control.markAsDirty(); |
||||
control.updateValueAndValidity({ onlySelf: true }); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 删除菜单 |
||||
*/ |
||||
showDelMenu() { |
||||
this.modal.confirm({ |
||||
nzTitle: '提示', |
||||
nzContent: '确实删除数据?', |
||||
nzOnOk: () => this.delMenu() |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 删除菜单 |
||||
*/ |
||||
delMenu() { |
||||
const param = { |
||||
menuId: this.menuDetail.id |
||||
} |
||||
this.treeView = false; |
||||
this.menuService.delMenu(param, (data: any) => { |
||||
if (data['return_code'] == '000000') { |
||||
// 刷新数据
|
||||
this.queryMenuTree(); |
||||
this.message.create('success', '操作成功'); |
||||
} else { |
||||
this.treeView = true; |
||||
this.message.create('error', data['return_msg']); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,12 @@ |
||||
import { NgModule } from '@angular/core'; |
||||
import { CommonModule } from '@angular/common'; |
||||
|
||||
|
||||
|
||||
@NgModule({ |
||||
declarations: [], |
||||
imports: [ |
||||
CommonModule |
||||
] |
||||
}) |
||||
export class SystemModule { } |
@ -0,0 +1,7 @@ |
||||
import { Routes } from '@angular/router'; |
||||
import {MenuComponent} from './menu/menu.component'; |
||||
|
||||
|
||||
export const SYSTEM_ROUTES: Routes = [ |
||||
{ path: 'menu', component: MenuComponent}, |
||||
]; |
@ -0,0 +1,16 @@ |
||||
import { Pipe, PipeTransform } from '@angular/core'; |
||||
|
||||
@Pipe({ |
||||
name: 'dataUtils', |
||||
standalone: true |
||||
}) |
||||
export class DataUtilsPipe implements PipeTransform { |
||||
|
||||
transform(data: any, length: number): any { |
||||
if (data.length == 0) { |
||||
return []; |
||||
} |
||||
return data.slice(0 , length); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,39 @@ |
||||
import { Pipe, PipeTransform } from '@angular/core'; |
||||
import {dictionaryData, Dictionary} from "../../data/common/dictionary.namespace"; |
||||
|
||||
@Pipe({ |
||||
name: 'dictionary', |
||||
standalone: true |
||||
}) |
||||
export class DictionaryPipe implements PipeTransform { |
||||
|
||||
data: Dictionary[] = dictionaryData; |
||||
|
||||
/** |
||||
* 获取数据字典 |
||||
* @param codeType 码类型 |
||||
*/ |
||||
getDictionaryList(codeType: string): any { |
||||
return this.data.filter(o => o.codeType == codeType); |
||||
} |
||||
|
||||
/** |
||||
* 获取数据字典 |
||||
* @param codeType 码类型 |
||||
* @param codeValue 码值 |
||||
*/ |
||||
getDictionary(codeType: string, codeValue: string): any { |
||||
// 读取缓存数据
|
||||
return this.data.find(o => o.codeType == codeType && o.codeValue == codeValue); |
||||
} |
||||
|
||||
transform(codeValue: string,codeType: string): string { |
||||
const obj = this.getDictionary(codeType, codeValue); |
||||
if (obj == null) { |
||||
return '未知'; |
||||
} else { |
||||
return obj.codeName; |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,115 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import {HttpClient} from "@angular/common/http"; |
||||
import {environment} from "../../../environments/environment"; |
||||
import {ObjectData} from "../../utils/objectData.service"; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class SysAccountService { |
||||
|
||||
constructor(private http: HttpClient) { } |
||||
|
||||
/** |
||||
* |
||||
* 编辑账户 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public editUser(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secUser/editUser', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 删除账户 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public delete(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secUser/delete', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 恢复账户 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public restore(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secUser/restore', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 禁用账户 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public disable(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secUser/disable', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 密码重置 |
||||
* @param userId |
||||
* @param callBack |
||||
*/ |
||||
public resetPwd(param: any, callBack:any) { |
||||
param.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secUser/resetPwd', param).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 查询详情 |
||||
* @param userId |
||||
* @param callBack |
||||
*/ |
||||
public queryDetail(userId: number, callBack:any) { |
||||
let params = { |
||||
userId: userId, |
||||
time: new Date().getTime() |
||||
}; |
||||
this.http.get(environment.baseUrl + 'secUser/queryDetail?'+ObjectData.objectByString(params)).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 查询列表 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public queryList(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.get(environment.baseUrl + 'secUser/queryList?'+ObjectData.objectByString(params)).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 查询账户登录列表 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public queryLoginLogList(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.get(environment.baseUrl + 'secUser/queryLoginLogList?'+ObjectData.objectByString(params)).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,25 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import {HttpClient} from '@angular/common/http'; |
||||
import {ObjectData} from '../../utils/objectData.service'; |
||||
import {environment} from '../../../environments/environment'; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class DictionaryService { |
||||
|
||||
constructor(private http: HttpClient) {} |
||||
|
||||
/** |
||||
* |
||||
* 查询数据字典 |
||||
* @param codeType 【非必填】 码值类型 |
||||
* @param callback |
||||
*/ |
||||
public getDictionary(codeType: string , callback: any): any { |
||||
this.http.get(environment.baseUrl + '/common/queryDictionary?codeType=' + codeType).subscribe( data => { |
||||
callback(data); |
||||
}); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,14 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import {NzIconService} from "ng-zorro-antd/icon"; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class IconService { |
||||
|
||||
constructor(private iconService: NzIconService) { |
||||
this.iconService.fetchFromIconfont({ |
||||
scriptUrl: 'https://at.alicdn.com/t/c/font_4647823_ys5j7ogeas.js' |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,52 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import {environment} from '../../environments/environment'; |
||||
import {HttpClient} from '@angular/common/http'; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class LoginService { |
||||
|
||||
constructor(private http: HttpClient) {} |
||||
|
||||
/** |
||||
* @Author Sum1Dream |
||||
* @Name userLogin |
||||
* @Description // 登录
|
||||
* @Date 15:52 2024/4/18 |
||||
* @Param params |
||||
* @Param callBack |
||||
*/ |
||||
public userLogin(params: object, callBack:any) { |
||||
this.http.post(environment.baseUrl + 'login/login', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* @Author Sum1Dream |
||||
* @Name loginOut |
||||
* @Description // 退出登录
|
||||
* @Date 15:52 2024/4/18 |
||||
* @Param callBack |
||||
*/ |
||||
public loginOut(callBack:any) { |
||||
this.http.post(environment.baseUrl + 'login/loginOut', null).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* @Author Sum1Dream |
||||
* @Name sendUserPass |
||||
* @Description // 修改用户密码
|
||||
* @Date 15:52 2024/4/18 |
||||
* @Param params |
||||
* @Param callBack |
||||
*/ |
||||
public sendUserPass(params: object, callBack:any) { |
||||
this.http.post(environment.baseUrl + 'secUser/sendUserPass', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,87 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import {HttpClient} from '@angular/common/http'; |
||||
import {environment} from '../../../environments/environment'; |
||||
import {ObjectData} from '../../utils/objectData.service'; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class MenuService { |
||||
|
||||
constructor(private http: HttpClient) {} |
||||
|
||||
/** |
||||
* 查询菜单树 |
||||
* @param roleId |
||||
* @param callBack |
||||
*/ |
||||
public queryMenuTree(callBack:any) { |
||||
this.http.post(environment.baseUrl + 'secMenu/queryMenuTree?dt='+new Date().getTime(), null).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 查询菜单 |
||||
* @param roleId |
||||
* @param callBack |
||||
*/ |
||||
public queryMenuList(callBack:any) { |
||||
let params = { |
||||
time: new Date().getTime() |
||||
}; |
||||
this.http.post(environment.baseUrl + 'secMenu/queryMenuList?' + ObjectData.objectByString(params), null).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 分配菜单 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public assignMenu(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secMenu/assignMenu', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 删除菜单 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public delMenu(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secMenu/delMenu', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 编辑菜单 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public editMenu(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secMenu/editMenu', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
/** |
||||
* 查询角色菜单权限数组 |
||||
* @param roleId |
||||
* @param callBack |
||||
*/ |
||||
public queryRoleMenuArray(roleId: number, callBack:any) { |
||||
const param = { |
||||
roleId: roleId, |
||||
t: new Date().getTime() // 时间戳避免缓存
|
||||
} |
||||
this.http.get(environment.baseUrl + 'secMenu/queryRoleMenuArray?' + ObjectData.objectByString(param)).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,73 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import {HttpClient} from "@angular/common/http"; |
||||
import {environment} from "../../../environments/environment"; |
||||
import {ObjectData} from "../../utils/objectData.service"; |
||||
|
||||
@Injectable({ |
||||
providedIn: 'root' |
||||
}) |
||||
export class RoleService { |
||||
|
||||
constructor(private http: HttpClient) { } |
||||
|
||||
/** |
||||
* 编辑角色 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public editRole(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secRole/editRole', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 删除角色 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public delRole(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.post(environment.baseUrl + 'secRole/delRole', params).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 查询详情 |
||||
* @param roleId |
||||
* @param callBack |
||||
*/ |
||||
public queryDetail(roleId: number, callBack:any) { |
||||
this.http.get(environment.baseUrl + 'secRole/queryDetail?roleId='+roleId).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 查询列表 |
||||
* @param params |
||||
* @param callBack |
||||
*/ |
||||
public queryList(params: any, callBack:any) { |
||||
params.time = new Date().getTime(); |
||||
this.http.get(environment.baseUrl + 'secRole/queryList?'+ObjectData.objectByString(params)).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 查询全部角色 |
||||
* @param callBack |
||||
*/ |
||||
public queryAllRole(callBack:any) { |
||||
let params = { |
||||
time: new Date().getTime() |
||||
}; |
||||
this.http.get(environment.baseUrl + 'secRole/queryAllRole?'+ObjectData.objectByString(params)).subscribe(data => { |
||||
callBack(data); |
||||
}); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@ |
||||
|
||||
import {HttpRequest, HttpHandlerFn, HttpEvent, HttpErrorResponse} from '@angular/common/http'; |
||||
import {catchError, Observable, throwError} from 'rxjs'; |
||||
import {Router} from '@angular/router'; |
||||
import {inject} from '@angular/core'; |
||||
import {USER_TOKEN} from '../data/login/localStorage.namespace'; |
||||
import {LocalStorageService} from './localStorage.service'; |
||||
|
||||
export function InterceptorService(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> { |
||||
const router = inject(Router); |
||||
const storage = inject(LocalStorageService); |
||||
const headers = req.headers.set('Authorization', String(storage.getItem(USER_TOKEN))); |
||||
const newReq = req.clone({headers}); |
||||
|
||||
return next(newReq).pipe( |
||||
catchError((error: HttpErrorResponse) => { |
||||
// 响应错误处理
|
||||
if (error.status === 401) { |
||||
router.navigate(['/error/401']); |
||||
} |
||||
if (error.status == 403) { |
||||
router.navigate(['/error/403']); |
||||
} |
||||
if (error.status == 404) { |
||||
router.navigate(['/error/404']); |
||||
} |
||||
if (error.status == 500) { |
||||
router.navigate(['/error/500']); |
||||
} |
||||
return throwError(() => error); |
||||
}) |
||||
); |
||||
|
||||
|
||||
} |
@ -0,0 +1,141 @@ |
||||
/** |
||||
* 选择类型 |
||||
*/ |
||||
export const DateSelectType: any = [ |
||||
{ value: 1, name: '今日'}, |
||||
{ value: 2, name: '昨日'}, |
||||
{ value: 3, name: '本周'}, |
||||
{ value: 4, name: '上周'}, |
||||
{ value: 5, name: '本月'}, |
||||
{ value: 6, name: '上月'}, |
||||
]; |
||||
|
||||
/** |
||||
* 时间工具类 |
||||
*/ |
||||
export class DateUtils { |
||||
|
||||
/** |
||||
* 获取时间 |
||||
* @param currentDate 当前时间 |
||||
* @param type 类型 1:今日 2:昨日 3:本周 4:上周 5:本月 6:上月 |
||||
*/ |
||||
public static getDate(currentDate: Date, type: number): any { |
||||
const returnObj = { |
||||
timeS: 0, |
||||
timeE: 0, |
||||
} |
||||
|
||||
if (type === 1) { |
||||
currentDate.setHours(0); |
||||
currentDate.setMinutes(0); |
||||
currentDate.setSeconds(0); |
||||
returnObj.timeS = currentDate.getTime(); |
||||
currentDate.setHours(23); |
||||
currentDate.setMinutes(59); |
||||
currentDate.setSeconds(59); |
||||
returnObj.timeE = currentDate.getTime(); |
||||
|
||||
} else if (type === 2) { |
||||
currentDate.setDate(currentDate.getDate() - 1) |
||||
currentDate.setHours(0); |
||||
currentDate.setMinutes(0); |
||||
currentDate.setSeconds(0); |
||||
returnObj.timeS = currentDate.getTime(); |
||||
currentDate.setHours(23); |
||||
currentDate.setMinutes(59); |
||||
currentDate.setSeconds(59); |
||||
returnObj.timeE = currentDate.getTime(); |
||||
|
||||
} else if (type === 3) { |
||||
const dayOfWeek = currentDate.getDay(); |
||||
const dayOffset = dayOfWeek === 0 ? -6 : 1 - dayOfWeek; |
||||
|
||||
const start = new Date(currentDate); |
||||
start.setDate(start.getDate() + dayOffset) |
||||
start.setHours(0); |
||||
start.setMinutes(0); |
||||
start.setSeconds(0); |
||||
returnObj.timeS = start.getTime(); |
||||
|
||||
const end = new Date(currentDate); |
||||
end.setDate(end.getDate() + 6) |
||||
end.setHours(23); |
||||
end.setMinutes(59); |
||||
end.setSeconds(59); |
||||
returnObj.timeE = end.getTime(); |
||||
|
||||
} else if (type === 4) { |
||||
const startOfThisWeek = new Date(currentDate.getFullYear(),currentDate.getMonth(),currentDate.getDate() - currentDate.getDay() + 1); |
||||
const endOfLastWeek = new Date(startOfThisWeek.getTime() - 1); |
||||
const startOfLastWeek = new Date((endOfLastWeek.getTime() + 1) - (7 * 24 * 60 * 60 * 1000)); |
||||
|
||||
startOfLastWeek .setHours(0); |
||||
startOfLastWeek .setMinutes(0); |
||||
startOfLastWeek .setSeconds(0); |
||||
returnObj.timeS = startOfLastWeek .getTime(); |
||||
|
||||
endOfLastWeek.setHours(23); |
||||
endOfLastWeek.setMinutes(59); |
||||
endOfLastWeek.setSeconds(59); |
||||
returnObj.timeE = endOfLastWeek.getTime(); |
||||
|
||||
} else if (type === 5) { |
||||
var daysInMonth = new Date(currentDate.getFullYear(), currentDate.getMonth()+1, 0).getDate(); |
||||
|
||||
const start = new Date(currentDate); |
||||
start.setDate(1) |
||||
start.setHours(0); |
||||
start.setMinutes(0); |
||||
start.setSeconds(0); |
||||
returnObj.timeS = start.getTime(); |
||||
|
||||
const end = new Date(currentDate); |
||||
end.setDate(daysInMonth) |
||||
end.setHours(23); |
||||
end.setMinutes(59); |
||||
end.setSeconds(59); |
||||
returnObj.timeE = end.getTime(); |
||||
|
||||
} else if (type === 6) { |
||||
var daysInMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 0).getDate(); |
||||
|
||||
const start = new Date(currentDate); |
||||
start.setMonth(currentDate.getMonth() - 1); |
||||
start.setDate(1) |
||||
start.setHours(0); |
||||
start.setMinutes(0); |
||||
start.setSeconds(0); |
||||
returnObj.timeS = start.getTime(); |
||||
|
||||
const end = new Date(currentDate); |
||||
end.setMonth(currentDate.getMonth() - 1); |
||||
end.setDate(daysInMonth) |
||||
end.setHours(23); |
||||
end.setMinutes(59); |
||||
end.setSeconds(59); |
||||
returnObj.timeE = end.getTime(); |
||||
} |
||||
|
||||
return returnObj; |
||||
} |
||||
|
||||
/** |
||||
* 获取时间 |
||||
* @param currentDate 当前时间 |
||||
* @param type 1;开始时间 2:结束时间 |
||||
*/ |
||||
public static getDateHMS(currentDate: Date , type: number): any { |
||||
if (type == 1) { |
||||
currentDate.setHours(0); |
||||
currentDate.setMinutes(0); |
||||
currentDate.setSeconds(0); |
||||
} |
||||
if (type == 2) { |
||||
currentDate.setHours(23); |
||||
currentDate.setMinutes(59); |
||||
currentDate.setSeconds(59); |
||||
} |
||||
return currentDate; |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
import { Injectable } from '@angular/core'; |
||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; |
||||
import {CanActivate} from "@angular/router"; |
||||
import {INIT_FLAG} from "../data/login/localStorage.namespace"; |
||||
import {LocalStorageService} from './localStorage.service'; |
||||
|
||||
|
||||
|
||||
@Injectable({ providedIn: 'root' }) |
||||
export class InitGuardService implements CanActivate { |
||||
constructor( |
||||
private storage: LocalStorageService, |
||||
private router: Router, |
||||
) { } |
||||
|
||||
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { |
||||
const init = !!this.storage.getItem(INIT_FLAG); |
||||
if (state.url.includes('login') && init) { |
||||
this.router.navigateByUrl('/admin/index').then(); |
||||
return false; |
||||
} |
||||
if (!state.url.includes('login') && !init) { |
||||
this.router.navigateByUrl('/login').then(); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,41 @@ |
||||
|
||||
// storage.service.ts
|
||||
import {Inject, Injectable, PLATFORM_ID} from '@angular/core'; |
||||
import {isPlatformBrowser} from '@angular/common'; |
||||
|
||||
@Injectable({ providedIn: 'root' }) |
||||
export class LocalStorageService { |
||||
|
||||
constructor(@Inject(PLATFORM_ID) private platformId: Object) {} |
||||
|
||||
getItem(key: string): string | null { |
||||
if (isPlatformBrowser(this.platformId)) { |
||||
const data = localStorage.getItem(key); |
||||
try { |
||||
return data ? JSON.parse(data) : null; |
||||
} catch (e) { |
||||
console.error('LocalStorage解析异常:', e); |
||||
return null; |
||||
} |
||||
} |
||||
return null; // 服务端返回默认值
|
||||
} |
||||
|
||||
setItem<T>(key: string, value: T): void { |
||||
try { |
||||
const data = JSON.stringify(value); |
||||
localStorage.setItem(key, data); |
||||
} catch (e) { |
||||
console.error('LocalStorage存储失败:', e); |
||||
} |
||||
} |
||||
|
||||
|
||||
removeItem(key: string): void { |
||||
localStorage.removeItem(key); |
||||
} |
||||
|
||||
clear(): void { |
||||
localStorage.clear(); |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
export class MathUtils{ |
||||
|
||||
/** |
||||
* @Author Sum1Dream |
||||
* @Name |
||||
* @Description // 获取1-100随机数
|
||||
* @Date 11:13 2024/4/9 |
||||
* @Param number |
||||
*/ |
||||
static generateRandomNumber(number: number): number { |
||||
return Math.floor(Math.random() * number) + 1; |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
export class ObjectData { |
||||
|
||||
/** |
||||
* @Author Sum1Dream |
||||
* @Name getWhereCondition |
||||
* @Description // 将对象转换成GET请求参数 key1=value1&key2=value2
|
||||
* @Date 14:02 2024/4/9 |
||||
* @Param object |
||||
*/ |
||||
static objectByString(object: any): string { |
||||
let str = ''; |
||||
for (const i in object) { |
||||
if (object[i] != null && object[i] !== '') { |
||||
if (str === '') { |
||||
str = i + '=' + object[i]; |
||||
} else { |
||||
str += '&' + i + '=' + object[i]; |
||||
} |
||||
} |
||||
} |
||||
return str; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,63 @@ |
||||
import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router'; |
||||
export class AiRouteReuseStrategy implements RouteReuseStrategy { |
||||
/** |
||||
* 用于保存路由快照 |
||||
**/ |
||||
public static routeSnapshots: { [key: string]: DetachedRouteHandle } = {}; |
||||
|
||||
/** |
||||
* 允许所有路由重用 |
||||
* 如果你有路由不想被重用,可以在这个方法中加业务逻辑判断 |
||||
**/ |
||||
shouldDetach(route: ActivatedRouteSnapshot): boolean { |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 以url为key保存路由,key也可以使用其他属性,能确保唯一即可 |
||||
**/ |
||||
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { |
||||
const url = this.getFullRouteUrl(route); |
||||
AiRouteReuseStrategy.routeSnapshots[url] = handle; |
||||
} |
||||
|
||||
/** |
||||
* 缓存中存在则允许还原路由 |
||||
**/ |
||||
shouldAttach(route: ActivatedRouteSnapshot): boolean { |
||||
const url = this.getFullRouteUrl(route); |
||||
return !!AiRouteReuseStrategy.routeSnapshots[url]; |
||||
} |
||||
|
||||
/** |
||||
* 从缓存中获取快照,没有返回null |
||||
**/ |
||||
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null { |
||||
const url = this.getFullRouteUrl(route); |
||||
return route.routeConfig ? AiRouteReuseStrategy.routeSnapshots[url] : null; |
||||
} |
||||
|
||||
/** |
||||
* 进入路由触发,判断是否同一路由 |
||||
**/ |
||||
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { |
||||
return future.routeConfig === curr.routeConfig && |
||||
JSON.stringify(future.params) === JSON.stringify(curr.params); |
||||
} |
||||
|
||||
private getFullRouteUrl(route: ActivatedRouteSnapshot): string { |
||||
return this.getFullRouteUrlPaths(route).filter(Boolean).join('/').replace(/\//g, '_'); |
||||
} |
||||
|
||||
private getFullRouteUrlPaths(route: ActivatedRouteSnapshot): string[] { |
||||
const paths = this.getRouteUrlPaths(route); |
||||
return route.parent |
||||
? [...this.getFullRouteUrlPaths(route.parent), ...paths] |
||||
: paths; |
||||
} |
||||
|
||||
private getRouteUrlPaths(route: ActivatedRouteSnapshot): string[] { |
||||
return route.url.map(urlSegment => urlSegment.path); |
||||
} |
||||
|
||||
} |
After Width: | Height: | Size: 143 KiB |
After Width: | Height: | Size: 928 KiB |
After Width: | Height: | Size: 953 KiB |
After Width: | Height: | Size: 836 KiB |
After Width: | Height: | Size: 913 KiB |
@ -0,0 +1,7 @@ |
||||
export const environment = { |
||||
production: true, |
||||
baseUrl: 'https://phgcs.dctpay.com/brest/', // 测试环境服务器地址(请求数据地址)
|
||||
orderUrl: 'https://phgcs.dctpay.com/order/', // 测试环境服务器地址(请求数据地址)
|
||||
userUrl: 'https://phgcs.dctpay.com/user/', // 测试环境服务器地址(请求数据地址)
|
||||
imageUrl: 'https://phg-test.obs.cn-southwest-2.myhuaweicloud.com/', |
||||
}; |
@ -0,0 +1,7 @@ |
||||
export const environment = { |
||||
production: true, |
||||
baseUrl: 'https://phg.dctpay.com/brest/', // 测试环境服务器地址(请求数据地址)
|
||||
orderUrl: 'https://phg.dctpay.com/order/', // 测试环境服务器地址(请求数据地址)
|
||||
userUrl: 'https://phg.dctpay.com/user/', // 测试环境服务器地址(请求数据地址)
|
||||
imageUrl: 'https://phg.obs.cn-southwest-2.myhuaweicloud.com/', |
||||
}; |
@ -0,0 +1,19 @@ |
||||
// This file can be replaced during build by using the `fileReplacements` array.
|
||||
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = { |
||||
production: false, |
||||
// baseUrl: 'https://phg.dctpay.com/brest/', // 测试环境服务器地址(请求数据地址)
|
||||
baseUrl: 'http://localhost:9702/brest/', // 测试环境服务器地址(请求数据地址)
|
||||
}; |
||||
|
||||
/* |
||||
* For easier debugging in development mode, you can import the following file |
||||
* to ignore zone related error stack fram es such as `zone.run`, `zoneDelegate.invokeTask`. |
||||
* |
||||
* This import should be commented out in production mode because it will have a negative impact |
||||
* on performance if an error is thrown. |
||||
*/ |
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
|
@ -0,0 +1,13 @@ |
||||
<!doctype html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<title>超冠体育</title> |
||||
<base href="/"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
||||
<link rel="icon" type="image/x-icon" href="favicon.ico"> |
||||
</head> |
||||
<body> |
||||
<app-root></app-root> |
||||
</body> |
||||
</html> |
@ -0,0 +1,7 @@ |
||||
import { bootstrapApplication } from '@angular/platform-browser'; |
||||
import { AppComponent } from './app/app.component'; |
||||
import { config } from './app/app.config.server'; |
||||
|
||||
const bootstrap = () => bootstrapApplication(AppComponent, config); |
||||
|
||||
export default bootstrap; |
@ -0,0 +1,6 @@ |
||||
import { bootstrapApplication } from '@angular/platform-browser'; |
||||
import { appConfig } from './app/app.config'; |
||||
import { AppComponent } from './app/app.component'; |
||||
|
||||
bootstrapApplication(AppComponent, appConfig) |
||||
.catch((err) => console.error(err)); |
@ -0,0 +1,66 @@ |
||||
import { |
||||
AngularNodeAppEngine, |
||||
createNodeRequestHandler, |
||||
isMainModule, |
||||
writeResponseToNodeResponse, |
||||
} from '@angular/ssr/node'; |
||||
import express from 'express'; |
||||
import { dirname, resolve } from 'node:path'; |
||||
import { fileURLToPath } from 'node:url'; |
||||
|
||||
const serverDistFolder = dirname(fileURLToPath(import.meta.url)); |
||||
const browserDistFolder = resolve(serverDistFolder, '../browser'); |
||||
|
||||
const app = express(); |
||||
const angularApp = new AngularNodeAppEngine(); |
||||
|
||||
/** |
||||
* Example Express Rest API endpoints can be defined here. |
||||
* Uncomment and define endpoints as necessary. |
||||
* |
||||
* Example: |
||||
* ```ts
|
||||
* app.get('/api/**', (req, res) => { |
||||
* // Handle API request
|
||||
* }); |
||||
* ``` |
||||
*/ |
||||
|
||||
/** |
||||
* Serve static files from /browser |
||||
*/ |
||||
app.use( |
||||
express.static(browserDistFolder, { |
||||
maxAge: '1y', |
||||
index: false, |
||||
redirect: false, |
||||
}), |
||||
); |
||||
|
||||
/** |
||||
* Handle all other requests by rendering the Angular application. |
||||
*/ |
||||
app.use('/**', (req, res, next) => { |
||||
angularApp |
||||
.handle(req) |
||||
.then((response) => |
||||
response ? writeResponseToNodeResponse(response, res) : next(), |
||||
) |
||||
.catch(next); |
||||
}); |
||||
|
||||
/** |
||||
* Start the server if this module is the main entry point. |
||||
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000. |
||||
*/ |
||||
if (isMainModule(import.meta.url)) { |
||||
const port = process.env['PORT'] || 4000; |
||||
app.listen(port, () => { |
||||
console.log(`Node Express server listening on http://localhost:${port}`); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions. |
||||
*/ |
||||
export const reqHandler = createNodeRequestHandler(app); |
@ -0,0 +1 @@ |
||||
/* You can add global styles to this file, and also import other style files */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue