| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937 |
- import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
- import { CommonModule, DatePipe } from '@angular/common';
- import {
- FormsModule,
- ReactiveFormsModule,
- FormBuilder,
- FormGroup,
- FormControl,
- Validators,
- } from '@angular/forms';
- import { Router, ActivatedRoute } from '@angular/router';
- import { Subscription } from 'rxjs';
- import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
- // NG-ZORRO 组件
- import { NzTableModule } from 'ng-zorro-antd/table';
- import { NzDividerModule } from 'ng-zorro-antd/divider';
- import { NzButtonModule } from 'ng-zorro-antd/button';
- import { NzIconModule } from 'ng-zorro-antd/icon';
- import { NzFormModule } from 'ng-zorro-antd/form';
- import { NzInputModule } from 'ng-zorro-antd/input';
- import { NzModalModule, NzModalService } from 'ng-zorro-antd/modal';
- import { NzSelectModule } from 'ng-zorro-antd/select';
- import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
- import { NzCardModule } from 'ng-zorro-antd/card';
- import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
- import { NzTagModule } from 'ng-zorro-antd/tag';
- import { NzTabsModule } from 'ng-zorro-antd/tabs';
- import { NzDescriptionsModule } from 'ng-zorro-antd/descriptions';
- import { NzMessageService } from 'ng-zorro-antd/message';
- import { NzEmptyModule } from 'ng-zorro-antd/empty';
- import { NzSpinModule } from 'ng-zorro-antd/spin';
- import { NzSwitchModule } from 'ng-zorro-antd/switch';
- // 服务
- import {
- MessageService,
- IMessageTemplate,
- TemplateType,
- TEMPLATE_TYPE_MAP,
- ActionType,
- ACTION_TYPE_MAP,
- ACTION_PARAM_PLACEHOLDERS,
- } from '../services/message.service';
- @Component({
- selector: 'app-message-template',
- standalone: true,
- imports: [
- CommonModule,
- FormsModule,
- ReactiveFormsModule,
- NzTableModule,
- NzDividerModule,
- NzButtonModule,
- NzIconModule,
- NzFormModule,
- NzInputModule,
- NzModalModule,
- NzSelectModule,
- NzPageHeaderModule,
- NzCardModule,
- NzPopconfirmModule,
- NzTagModule,
- NzTabsModule,
- NzDescriptionsModule,
- NzEmptyModule,
- NzSpinModule,
- NzSwitchModule,
- DatePipe,
- ],
- template: `
- <nz-page-header [nzGhost]="false">
- <nz-page-header-title>消息模板管理</nz-page-header-title>
- <nz-page-header-extra>
- <button nz-button nzType="primary" (click)="showCreateModal()">
- <span nz-icon nzType="plus"></span>新建模板
- </button>
- </nz-page-header-extra>
- <nz-page-header-content>
- 管理多语言消息模板,用于向不同语言的用户发送本地化消息
- </nz-page-header-content>
- </nz-page-header>
- <nz-card>
- <!-- 筛选表单 -->
- <form nz-form [formGroup]="filterForm" class="filter-form">
- <div nz-row [nzGutter]="16">
- <div nz-col [nzSpan]="8">
- <nz-form-item>
- <nz-form-control>
- <nz-input-group nzPrefixIcon="search">
- <input
- type="text"
- nz-input
- placeholder="模板名称"
- formControlName="templateName"
- />
- </nz-input-group>
- </nz-form-control>
- </nz-form-item>
- </div>
- <div nz-col [nzSpan]="8">
- <nz-form-item>
- <nz-form-control>
- <nz-select
- nzPlaceHolder="模板类型"
- formControlName="templateType"
- nzAllowClear
- >
- @for (type of templateTypeOptions; track type.value) {
- <nz-option
- [nzLabel]="type.label"
- [nzValue]="type.value"
- ></nz-option>
- }
- </nz-select>
- </nz-form-control>
- </nz-form-item>
- </div>
- <div nz-col [nzSpan]="8" class="button-col">
- <button nz-button (click)="resetFilters()">重置</button>
- </div>
- </div>
- </form>
- <nz-spin [nzSpinning]="isLoading">
- <nz-table
- #templatesTable
- [nzData]="filteredTemplates"
- [nzLoading]="isLoading"
- [nzFrontPagination]="false"
- [nzBordered]="true"
- [nzSize]="'small'"
- [nzShowPagination]="false"
- >
- <thead>
- <tr>
- <th>模板名称</th>
- <th>模板类型</th>
- <th>消息内容</th>
- <th style="text-align: center;">图片</th>
- <th style="text-align: center;">Action</th>
- <th style="text-align: center;">创建时间</th>
- <th style="text-align: center;">更新时间</th>
- <th style="text-align: center;">操作</th>
- </tr>
- </thead>
- <tbody>
- @for (template of templatesTable.data; track template.templateName)
- {
- <tr>
- <td>{{ template.templateName }}</td>
- <td>
- <nz-tag
- [nzColor]="'blue'"
- (click)="filterByType(template.templateType)"
- style="cursor: pointer;"
- >
- {{ getTemplateTypeName(template.templateType) }}
- </nz-tag>
- </td>
- <td class="message-content-cell">
- <div class="message-title">
- {{ template.messageTitle['en'] || '-' }}
- </div>
- <div class="message-content">
- {{ template.messageContent['en'] || '-' }}
- </div>
- </td>
- <td style="text-align: center;">
- @if (template.image) {
- <img
- [src]="template.image"
- style="max-width: 60px; max-height: 60px;"
- />
- } @else { - }
- </td>
- <td style="text-align: center;">{{ template.action }}</td>
- <td style="text-align: center;">
- {{ template.createdAt | date : 'yyyy-MM-dd HH:mm' }}
- </td>
- <td style="text-align: center;">
- {{ template.updatedAt | date : 'yyyy-MM-dd HH:mm' }}
- </td>
- <td style="text-align: center;">
- <a (click)="showEditModal(template)">编辑</a>
- <nz-divider nzType="vertical"></nz-divider>
- <a (click)="showDetailModal(template)">详情</a>
- <nz-divider nzType="vertical"></nz-divider>
- <a
- nz-popconfirm
- nzPopconfirmTitle="确定要删除此模板吗?"
- nzPopconfirmOkText="确定"
- nzPopconfirmCancelText="取消"
- (nzOnConfirm)="deleteTemplate(template.templateName)"
- >删除
- </a>
- </td>
- </tr>
- }
- </tbody>
- </nz-table>
- @if (filteredTemplates.length === 0 && !isLoading) {
- <nz-empty nzNotFoundContent="暂无消息模板"></nz-empty>
- }
- </nz-spin>
- </nz-card>
- <!-- 创建/编辑模板模态框 -->
- <nz-modal
- [(nzVisible)]="isModalVisible"
- [nzTitle]="isEditMode ? '编辑消息模板' : '新建消息模板'"
- [nzOkText]="isEditMode ? '更新' : '创建'"
- [nzCancelText]="'取消'"
- (nzOnCancel)="handleCancel()"
- (nzOnOk)="handleOk()"
- [nzOkLoading]="isSubmitting"
- [nzWidth]="800"
- >
- <form nz-form [formGroup]="templateForm" *nzModalContent>
- <nz-form-item>
- <nz-form-label nzRequired>模板名称</nz-form-label>
- <nz-form-control>
- <input
- nz-input
- formControlName="templateName"
- placeholder="输入模板名称(英文,不可重复)"
- />
- </nz-form-control>
- </nz-form-item>
- <nz-form-item>
- <nz-form-label nzRequired>模板类型</nz-form-label>
- <nz-form-control>
- <nz-select
- formControlName="templateType"
- nzPlaceHolder="选择模板类型"
- >
- @for (type of templateTypeOptions; track type.value) {
- <nz-option
- [nzLabel]="type.label"
- [nzValue]="type.value"
- ></nz-option>
- }
- </nz-select>
- </nz-form-control>
- </nz-form-item>
- <!-- 新增字段 -->
- <nz-form-item>
- <nz-form-label>图片URL</nz-form-label>
- <nz-form-control>
- <input
- nz-input
- formControlName="image"
- placeholder="输入图片URL(可选)"
- />
- </nz-form-control>
- </nz-form-item>
- <nz-form-item>
- <nz-form-label>允许展开</nz-form-label>
- <nz-form-control>
- <nz-switch formControlName="bigger"></nz-switch>
- </nz-form-control>
- </nz-form-item>
- <nz-form-item>
- <nz-form-label>客户端行为</nz-form-label>
- <nz-form-control>
- <nz-select formControlName="action" nzPlaceHolder="选择客户端行为">
- @for (action of getActionOptions(); track action.value) {
- <nz-option
- [nzLabel]="action.label"
- [nzValue]="action.value"
- ></nz-option>
- }
- </nz-select>
- </nz-form-control>
- </nz-form-item>
- <nz-form-item>
- <nz-form-label>参数</nz-form-label>
- <nz-form-control>
- <input
- nz-input
- formControlName="param"
- [placeholder]="getParamPlaceholder()"
- />
- </nz-form-control>
- </nz-form-item>
- <nz-form-item>
- <nz-form-label>扩展参数</nz-form-label>
- <nz-form-control>
- <input
- nz-input
- formControlName="extend"
- placeholder="输入扩展参数(可选)"
- />
- </nz-form-control>
- </nz-form-item>
- <nz-form-item>
- <nz-form-label nzRequired>添加语言</nz-form-label>
- <nz-form-control>
- <nz-select
- nzMode="multiple"
- nzPlaceHolder="选择要添加的语言"
- formControlName="selectedLanguages"
- (ngModelChange)="onLanguageSelectionChange()"
- >
- @for (lang of availableLanguages; track lang.code) {
- <nz-option
- [nzLabel]="lang.name"
- [nzValue]="lang.code"
- ></nz-option>
- }
- </nz-select>
- </nz-form-control>
- </nz-form-item>
- @if (templateForm.get('selectedLanguages')?.value; as selectedLangs) {
- @for (lang of selectedLangs; track lang) { @if
- (templateForm.get('title_' + lang) && templateForm.get('content_' +
- lang)) {
- <nz-card
- [nzTitle]="getLanguageName(lang)"
- [nzSize]="'small'"
- style="margin-bottom: 16px;"
- >
- <nz-form-item>
- <nz-form-label nzRequired>标题</nz-form-label>
- <nz-form-control>
- <textarea
- nz-input
- [formControlName]="'title_' + lang"
- placeholder="输入消息标题"
- rows="2"
- ></textarea>
- </nz-form-control>
- </nz-form-item>
- <nz-form-item>
- <nz-form-label nzRequired>内容</nz-form-label>
- <nz-form-control>
- <textarea
- nz-input
- [formControlName]="'content_' + lang"
- placeholder="输入消息内容"
- rows="4"
- ></textarea>
- </nz-form-control>
- </nz-form-item>
- </nz-card>
- } } }
- </form>
- </nz-modal>
- <!-- 模板详情模态框 -->
- <nz-modal
- [(nzVisible)]="isDetailModalVisible"
- [nzTitle]="'模板详情 - ' + (selectedTemplate?.templateName || '')"
- [nzFooter]="null"
- (nzOnCancel)="isDetailModalVisible = false"
- [nzWidth]="800"
- >
- <ng-container *nzModalContent>
- <nz-descriptions nzBordered [nzColumn]="1">
- <nz-descriptions-item nzTitle="模板名称">{{
- selectedTemplate?.templateName
- }}</nz-descriptions-item>
- <nz-descriptions-item nzTitle="模板类型">
- <nz-tag [nzColor]="'blue'">
- {{ getTemplateTypeName(selectedTemplate?.templateType || 0) }}
- </nz-tag>
- </nz-descriptions-item>
- @if (selectedTemplate?.image) {
- <nz-descriptions-item nzTitle="图片">
- <img
- [src]="selectedTemplate?.image"
- style="max-width: 100px; max-height: 100px;"
- />
- </nz-descriptions-item>
- }
- <nz-descriptions-item nzTitle="允许展开">
- {{ selectedTemplate?.bigger ? '是' : '否' }}
- </nz-descriptions-item>
- @if (selectedTemplate?.action) {
- <nz-descriptions-item nzTitle="动作类型">
- {{ selectedTemplate?.action }}
- </nz-descriptions-item>
- } @if (selectedTemplate?.param) {
- <nz-descriptions-item nzTitle="参数">
- {{ selectedTemplate?.param }}
- </nz-descriptions-item>
- } @if (selectedTemplate?.extend) {
- <nz-descriptions-item nzTitle="扩展参数">
- {{ selectedTemplate?.extend }}
- </nz-descriptions-item>
- }
- <nz-descriptions-item nzTitle="创建时间">{{
- selectedTemplate?.createdAt | date : 'yyyy-MM-dd HH:mm:ss'
- }}</nz-descriptions-item>
- <nz-descriptions-item nzTitle="更新时间">{{
- selectedTemplate?.updatedAt | date : 'yyyy-MM-dd HH:mm:ss'
- }}</nz-descriptions-item>
- </nz-descriptions>
- <nz-tabs>
- @for (lang of getLanguageKeys(selectedTemplate?.messageTitle || {});
- track lang) {
- <nz-tab [nzTitle]="getLanguageName(lang)">
- <nz-card [nzTitle]="'标题 (' + lang + ')'" [nzSize]="'small'">
- <p>{{ selectedTemplate?.messageTitle?.[lang] }}</p>
- </nz-card>
- <nz-card
- [nzTitle]="'内容 (' + lang + ')'"
- [nzSize]="'small'"
- style="margin-top: 16px;"
- >
- <p>{{ selectedTemplate?.messageContent?.[lang] }}</p>
- </nz-card>
- </nz-tab>
- }
- </nz-tabs>
- </ng-container>
- </nz-modal>
- `,
- styles: [
- `
- .filter-form {
- margin-bottom: 16px;
- }
- .button-col {
- display: flex;
- justify-content: flex-end;
- }
- nz-card {
- margin-bottom: 16px;
- }
- .ant-tag {
- margin-bottom: 4px;
- }
- .ant-form-item {
- margin-bottom: 16px;
- }
- textarea.ant-input {
- resize: none;
- }
- .ant-empty {
- margin: 40px 0;
- }
- .ant-table {
- margin-top: 16px;
- }
- /* 消息内容单元格样式 */
- .message-content-cell {
- max-width: 300px;
- min-width: 200px;
- }
- /* 消息标题样式 */
- .message-title {
- font-weight: bold;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- margin-bottom: 4px;
- }
- /* 消息内容样式 */
- .message-content {
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- overflow: hidden;
- text-overflow: ellipsis;
- line-height: 1.4;
- color: #666;
- }
- /* 可点击的标签样式 */
- nz-tag[style*='cursor: pointer']:hover {
- opacity: 0.8;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
- }
- img {
- max-width: 60px;
- max-height: 60px;
- border-radius: 4px;
- }
- `,
- ],
- })
- export class MessageTemplateComponent implements OnInit, OnDestroy {
- templates: IMessageTemplate[] = [];
- filteredTemplates: IMessageTemplate[] = [];
- isLoading = false;
- isModalVisible = false;
- isDetailModalVisible = false;
- isEditMode = false;
- isSubmitting = false;
- selectedTemplate: IMessageTemplate | null = null;
- availableLanguages: { code: string; name: string }[] = [];
- templateTypeOptions: { value: TemplateType; label: string }[] = [];
- // 筛选表单
- filterForm: FormGroup;
- // 模板表单
- templateForm: FormGroup;
- private queryParamsSubscription!: Subscription;
- constructor(
- private messageService: MessageService,
- private fb: FormBuilder,
- private message: NzMessageService,
- private modal: NzModalService,
- private cdr: ChangeDetectorRef,
- private router: Router,
- private route: ActivatedRoute
- ) {
- // 初始化筛选表单
- this.filterForm = this.fb.group({
- templateName: [''],
- templateType: [null],
- });
- // 初始化模板表单
- this.templateForm = this.fb.group({
- templateName: [
- '',
- [Validators.required, Validators.pattern(/^[a-zA-Z0-9_-]+$/)],
- ],
- templateType: [TemplateType.OTHER, Validators.required],
- image: [null],
- bigger: [false],
- action: [null],
- param: [null],
- extend: [null],
- selectedLanguages: [[], [Validators.required]],
- });
- }
- ngOnInit(): void {
- this.loadTemplates();
- this.availableLanguages = this.messageService.getSupportedLanguages();
- this.templateTypeOptions = this.messageService.getTemplateTypeOptions();
- // 监听筛选表单变化
- this.filterForm.valueChanges
- .pipe(
- debounceTime(300),
- // 自定义比较逻辑,确保值真正变化时才触发
- distinctUntilChanged((prev, curr) => {
- return (
- prev.templateName === curr.templateName &&
- prev.templateType === curr.templateType
- );
- })
- )
- .subscribe(() => {
- this.applyFilters();
- this.updateUrl();
- });
- // 订阅URL参数变化
- this.queryParamsSubscription = this.route.queryParams.subscribe(
- (params) => {
- this.filterForm.patchValue(
- {
- templateName: params['templateName'] || '',
- templateType: params['templateType']
- ? (parseInt(params['templateType'], 10) as TemplateType)
- : null,
- },
- { emitEvent: false }
- );
- this.loadTemplates();
- }
- );
- }
- ngOnDestroy(): void {
- if (this.queryParamsSubscription) {
- this.queryParamsSubscription.unsubscribe();
- }
- }
- //替换原来的方法
- getActionOptions(): { value: string; label: string }[] {
- return this.messageService.getActionOptions();
- }
- // 替换原来的方法
- getParamPlaceholder(): string {
- const action = this.templateForm.get('action')?.value as ActionType;
- return this.messageService.getActionParamPlaceholder(action);
- }
- loadTemplates(): void {
- this.isLoading = true;
- this.messageService.getAllTemplates().subscribe({
- next: (templates) => {
- this.templates = templates;
- this.applyFilters();
- this.isLoading = false;
- },
- error: (err) => {
- this.message.error('加载模板失败: ' + err.message);
- this.isLoading = false;
- },
- });
- }
- // 应用筛选条件
- applyFilters(): void {
- const filterValue = this.filterForm.value;
- this.filteredTemplates = this.templates.filter((template) => {
- const nameMatch = filterValue.templateName
- ? template.templateName
- .toLowerCase()
- .includes(filterValue.templateName.toLowerCase())
- : true;
- const typeMatch =
- filterValue.templateType !== null
- ? template.templateType === filterValue.templateType
- : true;
- return nameMatch && typeMatch;
- });
- }
- // 更新URL参数
- private updateUrl(): void {
- const queryParams: any = {};
- const filterValue = this.filterForm.value;
- if (filterValue.templateName) {
- queryParams.templateName = filterValue.templateName;
- }
- if (filterValue.templateType !== null) {
- queryParams.templateType = filterValue.templateType;
- }
- this.router.navigate([], {
- relativeTo: this.route,
- queryParams,
- queryParamsHandling: 'merge',
- });
- }
- // 点击类型标签筛选
- filterByType(type: TemplateType): void {
- this.filterForm.patchValue({
- templateType: type,
- });
- }
- // 重置筛选条件
- resetFilters(): void {
- this.filterForm.reset({
- templateName: '',
- templateType: null,
- });
- }
- getTemplateTypeName(type: TemplateType): string {
- return TEMPLATE_TYPE_MAP[type] || '未知类型';
- }
- showCreateModal(): void {
- this.isEditMode = false;
- // 关键修复:确保新建时模板名称控件可编辑
- const templateNameControl = this.templateForm.get('templateName');
- if (templateNameControl) {
- templateNameControl.enable();
- }
- // 重置表单默认值
- this.templateForm.reset({
- templateType: TemplateType.OTHER,
- bigger: false,
- });
- this.clearDynamicControls();
- // 设置默认语言
- const defaultLanguages = ['en', 'zh-cn'];
- this.templateForm.get('selectedLanguages')?.setValue(defaultLanguages);
- this.onLanguageSelectionChange();
- this.isModalVisible = true;
- }
- showEditModal(template: IMessageTemplate): void {
- this.isEditMode = true;
- this.selectedTemplate = template;
- this.templateForm.reset(
- {
- templateName: template.templateName,
- templateType: template.templateType,
- image: template.image || null,
- bigger: template.bigger || false,
- action: template.action || null,
- param: template.param || null,
- extend: template.extend || null,
- selectedLanguages: Object.keys(template.messageTitle),
- },
- { emitEvent: false }
- );
- // 编辑时禁用模板名称
- const templateNameControl = this.templateForm.get('templateName');
- if (templateNameControl) {
- templateNameControl.disable();
- }
- this.clearDynamicControls();
- // 加载多语言内容
- Object.keys(template.messageTitle).forEach((lang) => {
- this.templateForm.addControl(
- `title_${lang}`,
- new FormControl(template.messageTitle[lang], Validators.required)
- );
- this.templateForm.addControl(
- `content_${lang}`,
- new FormControl(template.messageContent[lang], Validators.required)
- );
- });
- this.cdr.detectChanges();
- this.isModalVisible = true;
- }
- showDetailModal(template: IMessageTemplate): void {
- this.selectedTemplate = template;
- this.isDetailModalVisible = true;
- }
- onLanguageSelectionChange(): void {
- // 统一语言代码为小写,避免大小写不一致导致的问题
- const selectedLanguages = (
- this.templateForm.get('selectedLanguages')?.value || []
- ).map((lang: string) => lang.toLowerCase());
- const currentLanguages = this.getCurrentLanguageControls();
- // 添加新选择的语言控件
- selectedLanguages.forEach((lang: string) => {
- if (!currentLanguages.includes(lang)) {
- this.addLanguageControls(lang);
- }
- });
- // 移除取消选择的语言控件
- currentLanguages.forEach((lang) => {
- if (!selectedLanguages.includes(lang)) {
- this.templateForm.removeControl(`title_${lang}`);
- this.templateForm.removeControl(`content_${lang}`);
- }
- });
- }
- handleOk(): void {
- if (this.templateForm.invalid) {
- this.markFormControlsAsDirty();
- return;
- }
- this.isSubmitting = true;
- const formValue = this.templateForm.getRawValue();
- const selectedLanguages = formValue.selectedLanguages;
- const messageData = {
- templateName: formValue.templateName,
- templateType: formValue.templateType,
- image: formValue.image,
- bigger: formValue.bigger,
- action: formValue.action,
- param: formValue.param,
- extend: formValue.extend,
- messageTitle: {} as { [key: string]: string },
- messageContent: {} as { [key: string]: string },
- };
- selectedLanguages.forEach((lang: string) => {
- const normalizedLang = lang.toLowerCase();
- const titleControl = this.templateForm.get(`title_${normalizedLang}`);
- const contentControl = this.templateForm.get(`content_${normalizedLang}`);
- if (titleControl && contentControl) {
- messageData.messageTitle[normalizedLang] = titleControl.value;
- messageData.messageContent[normalizedLang] = contentControl.value;
- }
- });
- if (this.isEditMode && this.selectedTemplate) {
- this.updateTemplate(messageData);
- } else {
- this.createTemplate(messageData);
- }
- }
- createTemplate(templateData: any): void {
- this.messageService.createTemplate(templateData).subscribe({
- next: () => {
- this.message.success('模板创建成功');
- this.loadTemplates();
- this.isModalVisible = false;
- this.isSubmitting = false;
- },
- error: (err) => {
- this.handleApiError(err, '创建');
- this.isSubmitting = false;
- },
- });
- }
- updateTemplate(templateData: any): void {
- if (!this.selectedTemplate) return;
- this.messageService
- .updateTemplate(this.selectedTemplate.templateName, templateData)
- .subscribe({
- next: () => {
- this.message.success('模板更新成功');
- this.loadTemplates();
- this.isModalVisible = false;
- this.isSubmitting = false;
- },
- error: (err) => {
- this.handleApiError(err, '更新');
- this.isSubmitting = false;
- },
- });
- }
- deleteTemplate(templateName: string): void {
- this.messageService.deleteTemplate(templateName).subscribe({
- next: () => {
- this.message.success('模板删除成功');
- this.loadTemplates();
- // 如果删除的是当前筛选的模板,重置筛选条件
- const currentFilterName = this.filterForm.get('templateName')?.value;
- if (
- currentFilterName &&
- currentFilterName.toLowerCase() === templateName.toLowerCase()
- ) {
- this.resetFilters();
- }
- },
- error: (err) => {
- this.handleApiError(err, '删除');
- },
- });
- }
- handleCancel(): void {
- this.isModalVisible = false;
- this.clearDynamicControls();
- // 重置表单状态,避免下次打开时显示错误提示
- Object.values(this.templateForm.controls).forEach((control) => {
- control.markAsPristine();
- control.markAsUntouched();
- });
- // 确保下次打开新建时模板名称可编辑
- const templateNameControl = this.templateForm.get('templateName');
- if (templateNameControl) {
- templateNameControl.enable();
- }
- }
- private addLanguageControls(lang: string): void {
- const normalizedLang = lang.toLowerCase();
- this.templateForm.addControl(
- `title_${normalizedLang}`,
- new FormControl('', Validators.required)
- );
- this.templateForm.addControl(
- `content_${normalizedLang}`,
- new FormControl('', Validators.required)
- );
- }
- private clearDynamicControls(): void {
- Object.keys(this.templateForm.controls).forEach((key) => {
- if (key.startsWith('title_') || key.startsWith('content_')) {
- this.templateForm.removeControl(key);
- }
- });
- }
- private getCurrentLanguageControls(): string[] {
- const languages: string[] = [];
- Object.keys(this.templateForm.controls).forEach((key) => {
- if (key.startsWith('title_')) {
- languages.push(key.replace('title_', '').toLowerCase());
- }
- });
- return languages;
- }
- private markFormControlsAsDirty(): void {
- Object.values(this.templateForm.controls).forEach((control) => {
- if (control instanceof FormControl) {
- control.markAsDirty();
- control.updateValueAndValidity();
- }
- });
- this.message.error('请填写所有必填字段');
- }
- private handleApiError(err: any, action: string): void {
- if (err.status === 409) {
- this.message.error('模板名称已存在');
- } else if (err.status === 404) {
- this.message.error('未找到指定的模板');
- } else if (err.status === 400) {
- this.message.error(
- '验证错误: ' + (err.error?.message || '请检查输入数据')
- );
- } else {
- this.message.error(`${action}模板失败: ${err.message}`);
- }
- }
- getLanguageName(code: string): string {
- return this.messageService.getLanguageName(code);
- }
- getLanguageKeys(obj: { [key: string]: any }): string[] {
- return obj ? Object.keys(obj) : [];
- }
- }
|