|
|
@@ -1,909 +0,0 @@
|
|
|
-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())
|
|
|
- .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);
|
|
|
- }
|
|
|
-
|
|
|
- // 模板表单初始化
|
|
|
- private initTemplateForm(): void {
|
|
|
- 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], // 现在会使用 ActionType 枚举
|
|
|
- param: [null],
|
|
|
- extend: [null],
|
|
|
- selectedLanguages: [[], [Validators.required]],
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- 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;
|
|
|
- this.templateForm.reset({
|
|
|
- templateType: TemplateType.OTHER,
|
|
|
- });
|
|
|
- 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 }
|
|
|
- );
|
|
|
-
|
|
|
- this.templateForm.get('templateName')?.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 || [];
|
|
|
- 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 titleControl = this.templateForm.get(`title_${lang}`);
|
|
|
- const contentControl = this.templateForm.get(`content_${lang}`);
|
|
|
-
|
|
|
- if (titleControl && contentControl) {
|
|
|
- messageData.messageTitle[lang] = titleControl.value;
|
|
|
- messageData.messageContent[lang] = 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();
|
|
|
- },
|
|
|
- error: (err) => {
|
|
|
- this.handleApiError(err, '删除');
|
|
|
- },
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- handleCancel(): void {
|
|
|
- this.isModalVisible = false;
|
|
|
- this.clearDynamicControls();
|
|
|
- }
|
|
|
-
|
|
|
- private addLanguageControls(lang: string): void {
|
|
|
- this.templateForm.addControl(
|
|
|
- `title_${lang}`,
|
|
|
- new FormControl('', Validators.required)
|
|
|
- );
|
|
|
- this.templateForm.addControl(
|
|
|
- `content_${lang}`,
|
|
|
- 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_', ''));
|
|
|
- }
|
|
|
- });
|
|
|
- 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) : [];
|
|
|
- }
|
|
|
-}
|