fix: 修复service模块重命名逻辑并成功集成core层API

主要修改:
1. 修复module-generator中服务重命名时的DI错误
   - 对于重命名的服务,直接使用别名注册,避免TypeScript找不到原始名称
   - 移除不必要的provide/useClass模式

2. 集成core层到主应用
   - 在app.module.ts中导入wwjcloud-core的AppModule
   - 在wwjcloud-core/src/index.ts中导出AppModule

3. 构建结果
   - 编译错误: 64+ -> 0
   - 注册路由: 15 -> 678
   - Docker服务全部正常启动
   - API接口正常响应
This commit is contained in:
wanwu
2025-10-26 20:40:23 +08:00
parent 0e8b6f5782
commit b735e24428
1712 changed files with 110857 additions and 273779 deletions

View File

@@ -1,57 +0,0 @@
# WWJCloud 框架里程碑 0.1.1
## 一、全局评估(当前基线)
- 分层清晰config配置与适配、core通用基础/抽象、vendor第三方适配、common业务域依赖方向 App→common→core→vendor 合规。
- 配置中心落地ConfigCenterService 统一读取与开关(如 swagger.enabled、swagger.token控制器与 UI 解耦;动态配置具备基础能力。
- API 文档输出:仅输出 JSON三端点分组全量/admin/frontend鉴权改为 Bearer Tokenswagger.token
- 观测与健康Winston 日志、Terminus 健康(/healthz /readyz /startupz、Metrics 基础可用。
- 任务与事件Outboxevents表、调度与重试字段/索引齐备;队列/事件基础设施在位。
- 安全基线全局守卫、RBAC文档 JSON 受 Token 保护Throttler 可用。
- 启动可观测:启动成功日志输出后端基地址与文档 JSON 三路由,便于联调。
## 二、风险与待确认
- 动态配置能力的“变更通知/缓存 TTL/审计记录”需在进入多域前补完细节。
- CI 质量门禁需在 PR 阶段强制ESLint/TS/coverage/e2e 阈值)。
- DB 初始化要强制走 migration避免纯 SQL 造成偏差。
- 文档 JSON 的密钥管理建议生产具备轮换机制。
- Nginx 反代模板建议固化(由 1Panel 管理也可)。
## 三、绿通项(已完成,可直接使用)
- Swagger JSON 鉴权与分组输出(/api-json、/api/admin-json、/api/frontend-json
- events 表(含 site_id、trace_id 等)完整建表与索引 SQL。
- 启动成功日志输出(服务地址与三条 JSON 路由)。
- 文档站联调(实时直连 + 备用离线脚本,带 Token
- 移除循环依赖隐患Swagger 纳入 config 核心模块barrel 不再导出 swagger module
## 四、网关Kong结论
- 单体阶段不必须启用1Panel/Nginx 反代 + 后端限流/鉴权足够。
- 多应用授权/域名授权阶段:建议引入网关统一鉴权/配额/策略,后端专注业务授权与审计。现有改造路径已预留。
## 五、PHP 框架迁移前置调整
- 数据与命名:表/字段/DTO/错误码与 PHP 对齐;返回格式统一。
- 鉴权与越权:管理端统一 JwtAuthGuard + RolesGuard`site_id` 租户隔离在业务流全链路透传与校验。
- 配置迁移PHP 配置项映射到 ConfigCenterService 键camelCase环境变量 UPPER_SNAKE_CASE生产设置 swagger.token。
- 依赖与集成:异步任务/事件对齐 Queue + Outbox只传 ID、支持幂等重试vendor 适配上传/存储/短信/支付。
- 测试与门禁:将 PHP 关键路径用例迁为 e2e/集成测试CI 强制 ESLint/TS/coverage/e2e 阈值。
- 文档对齐PHP 接口文档合流至当前 Swagger JSON 输出docs 站读取三份 JSON。
## 六、是否定稿 core/vendor/config进入 common 层?
- 结论可以。core/vendor/config 已达“可用基线”,足以支撑 common 层建设与业务迁移。
- core健康、拦截器/守卫/HTTP、队列与事件抽象、指标与 tracing 框架就绪。
- vendor第三方适配器骨架可用按业务逐步补实现。
- config配置中心、控制器出口、Swagger JSON 鉴权与分组稳定Barrel 导出已规避循环。
## 七、近期执行建议(进入 common
- 业务域落地顺序IAM用户/角色/权限)→ Settings → Upload → Notification → Schedule。
- 分层落地Controller路由+DTO→ AppService编排→ Core规则→ Infra持久化全链路 `site_id` 隔离。
- 测试覆盖:补关键用例(认证登录、权限越权、租户隔离、上传、事件投递/消费)单测/集成/e2e。
- 质量门禁:开启 ESLint/TS/coverage≥阈值 与 e2e 关键路径门禁。
- Nginx 反代模板:固化到仓库 docsHTTPS/超时/限流/大包/真实 IP 透传)。
## 八、版本说明0.1.1
- 特性Swagger JSON 分组与鉴权、配置中心接入、events 表与索引、启动可观测日志、docs 联调脚本支持 Token。
- 破坏性变更:移除旧 swagger integrations 引用与循环依赖;文档 JSON 访问需携带 Bearer Token。
- 升级指引:
1) 数据库执行 `events` 建表 SQL含 site_id/trace_id 等);
2) 配置中心设置 `swagger.token`
3) docs 侧按需携带 Bearer Token脚本已内置或通过环境变量

View File

@@ -2,46 +2,46 @@
## 📋 概述
本文档为AI开发者提供完整的智能体协作工作流程确保AI能够高效、规范地完成NestJS项目开发同时与PHP项目保持100%业务一致性。
本文档为AI开发者提供完整的智能体协作工作流程确保AI能够高效、规范地完成NestJS项目开发同时与Java项目保持100%业务一致性。
## 🎯 核心目标
- **框架层面**: 100% 使用 NestJS 的方式
- **业务层面**: 与 PHP 项目保持 100% 一致
- **数据层面**: 与 PHP 项目数据库结构 100% 一致
- **业务层面**: 与 Java 项目保持 100% 一致
- **数据层面**: 与 Java 项目数据库结构 100% 一致
## 🚫 AI开发严格约束条件必须遵守
### 绝对禁止的AI行为
1. **🚫 禁止自创业务逻辑** - 所有业务逻辑必须严格基于PHP项目真实代码
2. **🚫 禁止假设数据结构** - 所有数据结构必须基于 `g:\wwjcloud-nestjs\sql\wwjcloud.sql` 真实表结构
3. **🚫 禁止使用默认值** - 所有字段、方法、配置必须基于PHP项目真实值
1. **🚫 禁止自创业务逻辑** - 所有业务逻辑必须严格基于Java项目真实代码
2. **🚫 禁止假设数据结构** - 所有数据结构必须基于 `sql/wwjcloud.sql` 真实表结构
3. **🚫 禁止使用默认值** - 所有字段、方法、配置必须基于Java项目真实值
4. **🚫 禁止编写骨架代码** - 不允许生成空方法、TODO注释或占位符代码
5. **🚫 禁止写死数据** - 不允许硬编码任何业务数据或配置
6. **🚫 禁止猜测API接口** - 所有接口必须基于PHP控制器真实方法
6. **🚫 禁止猜测API接口** - 所有接口必须基于Java控制器真实方法
7. **🚫 禁止随意命名** - 所有命名必须遵循既定规范,不允许自由发挥
8. **🚫 禁止跳过验证** - 每个生成的文件都必须经过严格验证
### 必须遵循的数据源
- **数据库结构**: `g:\wwjcloud-nestjs\sql\wwjcloud.sql` (唯一权威数据源)
- **PHP控制器**: `niucloud-php\niucloud\app\adminapi\controller\` (API接口定义)
- **PHP服务层**: `niucloud-php\niucloud\app\service\` (业务逻辑实现)
- **PHP模型**: `niucloud-php\niucloud\app\model\` (数据模型定义)
- **PHP验证器**: `niucloud-php\niucloud\app\validate\` (数据验证规则)
- **数据库结构**: `sql/wwjcloud.sql` (唯一权威数据源)
- **Java控制器**: `niucloud-java/niucloud-core/src/main/java/.../controller/` (API接口定义)
- **Java服务层**: `niucloud-java/niucloud-core/src/main/java/.../service/` (业务逻辑实现)
- **Java实体**: `niucloud-java/niucloud-core/src/main/java/.../entity/` (数据模型定义)
- **Java验证器**: `niucloud-java/niucloud-core/src/main/java/.../validator/` (数据验证规则)
### AI开发质量标准
- **数据库字段映射准确率**: 100%
- **PHP方法对应准确率**: 100%
- **Java方法对应准确率**: 100%
- **业务逻辑一致性**: 100%
- **代码可直接运行**: 100%
- **命名规范符合率**: 100%
### AI开发检查清单
- [ ] 已查看对应的PHP源码文件
- [ ] 已查看对应的Java源码文件
- [ ] 已查看相关的数据库表结构
- [ ] 已理解真实的业务逻辑
- [ ] 已确认所有依赖关系
@@ -51,9 +51,9 @@
## 🤖 智能体角色定义(按执行顺序标注)
### S1 需求分析体(Analyzer)
- **职责**: 解析需求、对应 PHP/Nest 规范、输出任务切分与验收标准
- **输入**: 业务需求/接口变更/对齐 PHP 的说明
- **输出**: 模块划分、路由表、DTO、实体字段清单、与 DB/ThinkPHP 对照
- **职责**: 解析需求、对应 Java/Nest 规范、输出任务切分与验收标准
- **输入**: 业务需求/接口变更/对齐 Java 的说明
- **输出**: 模块划分、路由表、DTO、实体字段清单、与 DB/Spring Boot 对照
### S2 架构治理体(Architect)
- **职责**: 校验分层/依赖/目录规范,给出重构建议与边界清单
@@ -82,7 +82,7 @@
### S7 规范审计体(Auditor)
- **职责**: 按清单逐项核查,出具差异报告与修复项
- **检查**: 规范清单,字段/命名/路由/守卫/事务/队列/事件 与 PHP/DB 对齐
- **检查**: 规范清单,字段/命名/路由/守卫/事务/队列/事件 与 Java/DB 对齐
- **产物**: 差异报告与修复任务
### S8 上线管控体(Release)
@@ -122,12 +122,12 @@
- **层级内聚**模块内部按Spring Boot分层架构组织Controller→Service→Repository→Entity
- **模块间解耦**:模块间通过明确的接口和事件进行通信,避免直接依赖
### 2. 功能复写实现 → 参考 PHP项目 的业务逻辑
### 2. 功能复写实现 → 参考 Java项目 的业务逻辑
- 所有业务逻辑必须严格基于PHP项目真实代码
- API接口功能与PHP控制器保持100%一致
- 数据处理流程与PHP服务层保持100%一致
- 业务规则与PHP验证器保持100%一致
- 所有业务逻辑必须严格基于Java项目真实代码
- API接口功能与Java控制器保持100%一致
- 数据处理流程与Java服务层保持100%一致
- 业务规则与Java验证器保持100%一致
### 3. 框架特性使用 → 使用 NestJS 的技术特性
@@ -143,21 +143,21 @@
### auto-mapping-checker.js 使用指南
```bash
# 检查PHP和NestJS项目对应关系
# 检查Java和NestJS项目对应关系
node auto-mapping-checker.js
# 检查结果解读:
# ✅ 表示文件对应正确
# ❌ 表示PHP存在但NestJS缺失
# ❌ 表示Java存在但NestJS缺失
# 📊 统计信息:检查模块数、发现问题数
```
### 工具检查维度
- **模块对应性**: PHP模块与NestJS模块一一对应
- **模块对应性**: Java模块与NestJS模块一一对应
- **分层完整性**: 控制器、服务、实体等层级完整
- **文件命名规范**: 确保命名符合各自框架规范
- **业务逻辑一致性**: 功能实现与PHP项目保持一致
- **业务逻辑一致性**: 功能实现与Java项目保持一致
## 📚 相关文档
@@ -176,7 +176,7 @@ node auto-mapping-checker.js
## 🔗 核心约束
-PHP 业务/数据100%一致;与 NestJS 规范100%匹配
-Java 业务/数据100%一致;与 NestJS 规范100%匹配
- 禁止创建 DB 不存在字段;`sys_config.value(JSON)` 统一
- 管理端路由 `/adminapi`,前台 `/api`;统一守卫与响应格式

View File

@@ -2,17 +2,7 @@
## 认证架构对比
### 1. PHP ThinkPHP (传统方式)
```php
// 通过中间件全局处理
class AdminCheckToken {
public function handle(Request $request, Closure $next) {
// 检查token某些路由可以跳过
}
}
```
### 2. Java Spring Boot (注解方式)
### 1. Java Spring Boot (注解方式)
```java
@RestController
public class AuthController {
@@ -26,7 +16,7 @@ public class AuthController {
}
```
### 3. NestJS (装饰器方式) - 更像Java
### 2. NestJS (装饰器方式) - 更像Java
```typescript
@Controller('adminapi/auth')
export class AuthController {
@@ -104,15 +94,15 @@ export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
### 路由路径对齐
#### PHP → NestJS 路径映射
#### Java → NestJS 路径映射
```typescript
// PHP: /adminapi/sys/get/website
// Java: /adminapi/sys/get/website
// NestJS: @Get('get/website') 在 @Controller('adminapi/sys')
// PHP: /adminapi/login
// Java: /adminapi/login
// NestJS: @Get('login') 在 @Controller('adminapi') + @Public()
// PHP: /adminapi/captcha/create
// Java: /adminapi/captcha/create
// NestJS: @Get('create') 在 @Controller('adminapi/captcha') + @Public()
```
@@ -145,9 +135,9 @@ export class ConfigController {
```
#### 3. 路径命名规范
- **PHP方法名**: `getWebsite()`**NestJS路径**: `get/website`
- **PHP方法名**: `setWebsite()`**NestJS路径**: `set/website`
- **PHP方法名**: `getSceneDomain()`**NestJS路径**: `get/scene/domain`
- **Java方法名**: `getWebsite()`**NestJS路径**: `get/website`
- **Java方法名**: `setWebsite()`**NestJS路径**: `set/website`
- **Java方法名**: `getSceneDomain()`**NestJS路径**: `get/scene/domain`
### 验证方法
@@ -168,10 +158,10 @@ curl -H "Authorization: Bearer <token>" http://localhost:3001/adminapi/site/list
### 总结
NestJS的认证处理方式**更像Java Spring Boot**,使用装饰器模式:
NestJS的认证处理方式**Java Spring Boot相同**,使用装饰器模式:
1. **@Public()** = Java的 **@SaNotCheckLogin**
2. **默认需要登录** = Java的 **@SaCheckLogin**
3. **全局守卫** = Java的 **拦截器**
这种方式比PHP的中间件方式更加灵活类型安全,符合现代框架的设计理念。
这种方式灵活类型安全,符合现代框架的设计理念。

View File

@@ -8,11 +8,11 @@
### 1. 框架使用原则
- **框架层面**: 100% 使用 NestJS 的方式和特性
- **业务层面**: 与 PHP 项目保持 100% 一致
- **数据层面**: 与 PHP 项目数据库结构 100% 一致
- **业务层面**: 与 Java 项目保持 100% 一致
- **数据层面**: 与 Java 项目数据库结构 100% 一致
### 2. 开发约束条件
-**必须**: 基于 PHP 项目真实代码进行开发
-**必须**: 基于 Java 项目真实代码进行开发
-**必须**: 基于真实数据库表结构进行映射
-**必须**: 遵循项目既定的命名规范
-**禁止**: 自创业务逻辑或数据结构
@@ -107,7 +107,7 @@ src/
#### 1. 业务方法
- **格式**: `camelCase`
- **原则**: 与 PHP 项目方法名保持一致
- **原则**: 与 Java 项目方法名保持一致
- **示例**: `getUserList()`, `addUser()`, `updateConfig()`
#### 2. 私有方法
@@ -126,7 +126,7 @@ src/
#### 2. 业务变量
- **格式**: `camelCase`
- **原则**: 与 PHP 项目变量名保持一致
- **原则**: 与 Java 项目变量名保持一致
- **示例**: `userId`, `userName`, `configKey`
#### 3. 常量
@@ -136,12 +136,12 @@ src/
### 数据库相关命名
#### 1. 表名映射
- **原则**: 与 PHP 项目表名 100% 一致
- **原则**: 与 Java 项目表名 100% 一致
- **示例**: `nc_sys_config`, `nc_sys_user`, `nc_member_level`
- **说明**: 不能修改任何表名或前缀
#### 2. 字段名映射
- **原则**: 与 PHP 项目字段名 100% 一致
- **原则**: 与 Java 项目字段名 100% 一致
- **示例**: `site_id`, `config_key`, `create_time`, `update_time`
- **说明**: 不能修改任何字段名或类型
@@ -214,7 +214,7 @@ export class CreateUserDto {
## 📋 开发检查清单
### 开发前检查
- [ ] 已查看对应的 PHP 源码文件
- [ ] 已查看对应的 Java 源码文件
- [ ] 已查看相关的数据库表结构
- [ ] 已理解真实的业务逻辑
- [ ] 已确认所有依赖关系
@@ -222,9 +222,9 @@ export class CreateUserDto {
### 开发中检查
- [ ] 文件命名符合项目规范
- [ ] 类命名符合项目规范
- [ ] 方法命名与 PHP 项目一致
- [ ] 方法命名与 Java 项目一致
- [ ] 数据库字段映射准确
- [ ] 业务逻辑与 PHP 项目一致
- [ ] 业务逻辑与 Java 项目一致
### 开发后检查
- [ ] 代码可以正常编译
@@ -245,16 +245,16 @@ export class CreateUserDto {
### 3. 业务逻辑错误
- ❌ 错误: 自创业务逻辑
- ✅ 正确: 基于 PHP 项目真实代码
- ✅ 正确: 基于 Java 项目真实代码
### 4. 数据库映射错误
- ❌ 错误: 修改表名或字段名
- ✅ 正确: 与 PHP 项目 100% 一致
- ✅ 正确: 与 Java 项目 100% 一致
## 📚 参考资源
- **项目仓库**: wwjcloud-nsetjs
- **PHP 项目**: niucloud-php
- **Java 项目**: niucloud-java
- **数据库结构**: `sql/wwjcloud.sql`
- **NestJS 官方文档**: https://nestjs.com/
- **TypeORM 文档**: https://typeorm.io/

Submodule niucloud-java updated: db961c9080...5b107c9379

Submodule niucloud-php deleted from 585ceba4be

View File

@@ -8,15 +8,20 @@ const RouteConsistencyUtils = require('../utils/route-consistency-utils');
* 将Java控制器转换为NestJS控制器
*/
class ControllerGenerator {
constructor() {
constructor(outputDir) {
this.namingUtils = new NamingUtils();
this.routeUtils = new RouteConsistencyUtils();
this.outputDir = outputDir || '';
}
/**
* 生成控制器文件
*/
generateController(javaController, outputDir) {
// 如果this.outputDir已经被设置不要覆盖它用于findServiceFile
// outputDir参数用于控制器文件的输出目录
const controllerOutputDir = outputDir || this.outputDir;
// 检查控制器数据是否有效
if (!javaController || !javaController.className) {
console.warn(`⚠️ 跳过无效控制器: ${JSON.stringify(javaController)}`);
@@ -25,7 +30,7 @@ class ControllerGenerator {
// 根据Java文件路径创建子目录结构
const subDir = this.getSubDirectoryFromJavaPath(javaController.filePath, 'controller');
const fullOutputDir = path.join(outputDir, subDir);
const fullOutputDir = path.join(controllerOutputDir, subDir);
// 确保子目录存在
if (!fs.existsSync(fullOutputDir)) {
@@ -90,6 +95,149 @@ ${methods}
}
/**
* 查找Service文件的实际路径
* 支持宽松匹配,忽略连字符差异
* @returns {string|null} 相对于services目录的路径
*/
findServiceFile(serviceName) {
if (!this.outputDir) return null;
const servicesDir = path.join(this.outputDir, 'services');
if (!fs.existsSync(servicesDir)) return null;
// 规范化文件名用于比较移除连字符、下划线、impl、service等后缀统一为小写
const normalizeForComparison = (name) => {
return name.toLowerCase()
.replace(/[-_]/g, '')
.replace(/serviceimpl/g, '')
.replace(/impl/g, '')
.replace(/service\.ts/g, '.ts')
.replace(/service/g, '');
};
const targetNormalized = normalizeForComparison(serviceName);
const searchDir = (dir) => {
const files = fs.readdirSync(dir);
for (const file of files) {
const fullPath = path.join(dir, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
const result = searchDir(fullPath);
if (result) return result;
} else if (normalizeForComparison(file) === targetNormalized) {
return path.relative(servicesDir, fullPath);
}
}
return null;
};
return searchDir(servicesDir);
}
/**
* 从Service文件中提取实际的类名
* @param {string} serviceFilePath - Service文件的完整路径
* @returns {string|null} - 导出的类名
*/
extractServiceClassName(serviceFilePath) {
if (!fs.existsSync(serviceFilePath)) return null;
try {
const content = fs.readFileSync(serviceFilePath, 'utf-8');
// 匹配: export class XxxService
const classMatch = content.match(/export\s+class\s+(\w+)/);
return classMatch ? classMatch[1] : null;
} catch (error) {
console.warn(`⚠️ 无法读取Service文件: ${serviceFilePath}`);
return null;
}
}
/**
* 获取Service的实际类名优先从文件读取否则推断
* @param {string} dep - 依赖的Java类名如 AddonServiceImpl
* @returns {string} - 实际的TypeScript类名
*/
getActualServiceClassName(dep) {
const serviceFileName = this.namingUtils.generateFileName(dep, 'service');
let serviceName = this.namingUtils.generateServiceName(dep); // 默认推断的类名
if (this.outputDir) {
const servicesDir = path.join(this.outputDir, 'services');
const serviceRelativePath = this.findServiceFile(serviceFileName);
if (serviceRelativePath) {
const serviceFullPath = path.join(servicesDir, serviceRelativePath);
const actualClassName = this.extractServiceClassName(serviceFullPath);
if (actualClassName) {
serviceName = actualClassName; // 使用实际的类名
}
}
}
return serviceName;
}
/**
* 计算从Controller到Service的相对路径
*/
calculateServicePath(javaFilePath, serviceFileName) {
const cleanFileName = serviceFileName.replace('.ts', '');
// 先尝试查找实际的service文件
const actualServicePath = this.findServiceFile(serviceFileName);
if (actualServicePath) {
if (!javaFilePath) return `../../../services/${actualServicePath.replace(/\\/g, '/').replace('.ts', '')}`;
const pathParts = javaFilePath.split(path.sep);
const javaIndex = pathParts.findIndex(part => part === 'java');
if (javaIndex === -1) return `../../../services/${actualServicePath.replace(/\\/g, '/').replace('.ts', '')}`;
const packageParts = pathParts.slice(javaIndex + 1, -1);
const controllerIndex = packageParts.findIndex(part => part === 'controller' || part === 'controllers');
if (controllerIndex === -1) return `../../../services/${actualServicePath.replace(/\\/g, '/').replace('.ts', '')}`;
const subParts = packageParts.slice(controllerIndex + 1);
const depth = subParts.length + 1;
const upLevels = '../'.repeat(depth);
return `${upLevels}services/${actualServicePath.replace(/\\/g, '/').replace('.ts', '')}`;
}
// 回退到推断路径
if (!javaFilePath) return `../../../services/admin/impl/${cleanFileName}`;
const pathParts = javaFilePath.split(path.sep);
const javaIndex = pathParts.findIndex(part => part === 'java');
if (javaIndex === -1) return `../../../services/admin/impl/${cleanFileName}`;
const packageParts = pathParts.slice(javaIndex + 1, -1);
const controllerIndex = packageParts.findIndex(part => part === 'controller' || part === 'controllers');
if (controllerIndex === -1) return `../../../services/admin/impl/${cleanFileName}`;
const subParts = packageParts.slice(controllerIndex + 1);
const depth = subParts.length + 1;
const upLevels = '../'.repeat(depth);
let serviceSubPath = subParts.map(part => part === 'adminapi' ? 'admin' : part).join('/');
if (serviceSubPath) {
serviceSubPath += '/impl';
} else {
serviceSubPath = 'admin/impl';
}
return `${upLevels}services/${serviceSubPath}/${cleanFileName}`;
}
/**
* 计算Result类的相对路径
*/
@@ -130,15 +278,35 @@ ${methods}
"import { AuthGuard, RbacGuard, Result } from '@wwjBoot';"
];
// 添加服务导入
if (javaController.dependencies && javaController.dependencies.length > 0) {
javaController.dependencies.forEach(dep => {
const serviceName = this.namingUtils.generateServiceName(dep);
const serviceFileName = this.namingUtils.generateFileName(dep, 'service');
imports.push(`import { ${serviceName} } from '../services/${serviceFileName.replace('.service.ts', '')}';`);
});
// 获取依赖列表,如果为空则从控制器名称推断
let dependencies = javaController.dependencies || [];
if (dependencies.length === 0) {
// 从控制器名称推断 Service 依赖
// Controller -> ControllerServiceImpl匹配Java Service命名规范
const controllerName = javaController.className.replace(/Controller$/, '');
dependencies = [controllerName + 'ServiceImpl'];
}
// 添加服务导入 - 计算正确的相对路径
dependencies.forEach(dep => {
const serviceFileName = this.namingUtils.generateFileName(dep, 'service');
// 检查Service文件是否存在
const serviceRelativePath = this.findServiceFile(serviceFileName);
if (!serviceRelativePath) {
console.warn(`⚠️ Service文件未找到: ${serviceFileName} (Controller: ${javaController.className})`);
return; // 跳过该导入
}
const relativePath = this.calculateServicePath(javaController.filePath, serviceFileName);
const serviceName = this.getActualServiceClassName(dep);
if (serviceName) {
imports.push(`import { ${serviceName} } from '${relativePath}';`);
}
});
// 添加DTO导入
if (javaController.dtos && javaController.dtos.length > 0) {
javaController.dtos.forEach(dto => {
@@ -157,9 +325,10 @@ ${methods}
generateDecorators(routeInfo) {
const decorators = [];
// 控制器装饰器
// 控制器装饰器 - 去掉前导斜杠
if (routeInfo.controllerPath) {
decorators.push(`@Controller('${routeInfo.controllerPath}')`);
const cleanPath = routeInfo.controllerPath.replace(/^\/+/, '');
decorators.push(`@Controller('${cleanPath}')`);
} else {
decorators.push('@Controller()');
}
@@ -168,8 +337,8 @@ ${methods}
decorators.push('@ApiTags(\'API\')');
decorators.push('@ApiBearerAuth()');
// 守卫装饰器
decorators.push('@UseGuards(AuthGuard, RbacGuard)');
// 移除重复的守卫装饰器 - 使用全局守卫
// @UseGuards(AuthGuard, RbacGuard) 已在全局配置
return decorators.join('\n');
}
@@ -199,21 +368,44 @@ ${methods}
const parameters = this.generateMethodParameters(method);
const returnType = this.generateReturnType(method);
return ` ${httpDecorator}('${method.path}')
// 将 /{key} 格式转换为 NestJS 的 :key 格式,并移除前导斜杠
const nestPath = method.path.replace(/\{(\w+)\}/g, ':$1').replace(/^\/+/, '');
// 生成方法体使用实际的Java Service调用
const methodBody = this.generateMethodBody(method, javaController);
return ` ${httpDecorator}('${nestPath}')
@ApiOperation({ summary: '${method.path}' })
@ApiResponse({ status: 200, description: '成功' })
async ${methodName}(${parameters}): Promise<${returnType}> {
try {
// TODO: 实现业务逻辑
const result = await this.${this.getCorrectServiceName(javaController)}.${methodName}(${this.generateServiceMethodParameters(method)});
return Result.success(result);
} catch (error) {
// 确保错误响应格式与Java一致
return Result.error(error.message || '操作失败');
}
${methodBody}
}`;
}
/**
* 生成方法体
*/
generateMethodBody(method, javaController) {
const javaMethodName = method.javaMethodName;
const methodServiceCalls = javaController.methodServiceCalls || {};
const serviceCalls = methodServiceCalls[javaMethodName] || [];
if (serviceCalls.length === 0) {
// 没有找到Service调用返回占位符
return ` // TODO: 实现业务逻辑
return Result.success(null);`;
}
// 使用第一个Service调用通常Controller方法只调用一个主Service方法
const firstCall = serviceCalls[0];
const servicePropertyName = this.namingUtils.toCamelCase(firstCall.serviceImpl) + 'Service';
const serviceMethodName = firstCall.serviceMethod;
const methodParams = this.generateServiceMethodParameters(method);
return ` const result = await this.${servicePropertyName}.${serviceMethodName}(${methodParams});
return Result.success(result);`;
}
/**
* 生成有效的方法名
*/
@@ -288,16 +480,30 @@ ${methods}
// 根据HTTP方法添加参数
if (method.httpMethod.toLowerCase() === 'post' || method.httpMethod.toLowerCase() === 'put') {
parameters.push('@Body() body: any');
// 如果有对应的DTO使用DTO类型否则使用Record类型代替any
const dtoType = method.requestDto || 'Record<string, any>';
parameters.push(`@Body() body: ${dtoType}`);
}
// 添加路径参数
// 添加路径参数 - 使用具体类型
if (method.path.includes('{')) {
parameters.push('@Param() params: any');
// 提取路径参数名称
const paramNames = method.path.match(/\{(\w+)\}/g);
if (paramNames && paramNames.length === 1) {
// 单个参数,直接使用具体类型
const paramName = paramNames[0].replace(/[{}]/g, '');
parameters.push(`@Param('${paramName}') ${paramName}: string`);
} else {
// 多个参数,使用对象类型
parameters.push('@Param() params: Record<string, string>');
}
}
// 添加查询参数
parameters.push('@Query() query: any');
// 添加查询参数 - 使用Record类型代替any
if (method.httpMethod.toLowerCase() === 'get') {
const queryType = method.queryDto || 'Record<string, any>';
parameters.push(`@Query() query: ${queryType}`);
}
return parameters.join(', ');
}
@@ -313,11 +519,17 @@ ${methods}
* 获取正确的服务属性名
*/
getCorrectServiceName(javaController) {
if (!javaController.dependencies || javaController.dependencies.length === 0) {
return 'serviceService';
// 获取依赖列表,如果为空则从控制器名称推断
let dependencies = javaController.dependencies || [];
if (dependencies.length === 0) {
// 从控制器名称推断服务名
// Controller -> ControllerServiceImpl匹配Java Service命名规范
const controllerName = javaController.className.replace(/Controller$/, '');
return this.namingUtils.toCamelCase(controllerName + 'ServiceImpl') + 'Service';
}
const firstDep = javaController.dependencies[0];
const firstDep = dependencies[0];
return this.namingUtils.toCamelCase(firstDep) + 'Service';
}
@@ -332,13 +544,23 @@ ${methods}
parameters.push('body');
}
// 添加路径参数
// 添加路径参数 - 使用实际的参数名
if (method.path.includes('{')) {
parameters.push('params');
const paramNames = method.path.match(/\{(\w+)\}/g);
if (paramNames && paramNames.length === 1) {
// 单个参数,使用参数名
const paramName = paramNames[0].replace(/[{}]/g, '');
parameters.push(paramName);
} else if (paramNames && paramNames.length > 1) {
// 多个参数使用params对象
parameters.push('params');
}
}
// 添加查询参数
parameters.push('query');
// 添加查询参数 - 只在GET请求时添加
if (method.httpMethod.toLowerCase() === 'get') {
parameters.push('query');
}
return parameters.join(', ');
}
@@ -347,34 +569,36 @@ ${methods}
* 生成构造函数
*/
generateConstructor(javaController) {
if (!javaController.dependencies || javaController.dependencies.length === 0) {
// 即使没有依赖,也生成一个基本的构造函数和服务属性
return ` private readonly serviceService: any; // 默认服务属性
constructor() {
// 基本构造函数
}`;
// 获取依赖列表,如果为空则从控制器名称推断
let dependencies = javaController.dependencies || [];
if (dependencies.length === 0) {
// 从控制器名称推断 Service 依赖
// Controller -> ControllerServiceImpl匹配Java Service命名规范
const controllerName = javaController.className.replace(/Controller$/, '');
dependencies = [controllerName + 'ServiceImpl'];
}
const serviceInjections = javaController.dependencies.map(dep => {
const serviceName = this.namingUtils.generateServiceName(dep);
const servicePropertyName = this.namingUtils.toCamelCase(dep) + 'Service';
return ` private readonly ${servicePropertyName}: ${serviceName};`;
const constructorParams = [];
dependencies.forEach(dep => {
// 检查Service文件是否存在
const serviceFileName = this.namingUtils.generateFileName(dep, 'service');
const serviceRelativePath = this.findServiceFile(serviceFileName);
if (serviceRelativePath) {
const serviceName = this.getActualServiceClassName(dep); // 使用实际类名
const servicePropertyName = this.namingUtils.toCamelCase(dep) + 'Service';
constructorParams.push(` private readonly ${servicePropertyName}: ${serviceName}`);
}
});
const constructorParams = javaController.dependencies.map(dep => {
const serviceName = this.namingUtils.generateServiceName(dep);
const servicePropertyName = this.namingUtils.toCamelCase(dep) + 'Service';
return ` private readonly ${servicePropertyName}: ${serviceName}`;
});
if (constructorParams.length === 0) {
return ' constructor() {}';
}
return ` private readonly serviceService: any; // 默认服务属性
constructor(
return ` constructor(
${constructorParams.join(',\n')}
) {
${serviceInjections.map(injection => ` ${injection}`).join('\n')}
}`;
) {}`;
}
/**

View File

@@ -31,12 +31,10 @@ class DtoGenerator {
*/
generateDtoContent(javaDto, dtoName) {
const imports = this.generateImports(javaDto);
const decorators = this.generateDecorators(javaDto);
const fields = this.generateFields(javaDto);
return `${imports}
${decorators}
export class ${dtoName} extends BaseDto {
${fields}
}
@@ -50,7 +48,7 @@ ${fields}
const imports = [
"import { IsString, IsNumber, IsBoolean, IsOptional, IsArray, IsDateString, IsEmail, IsUrl, IsEnum } from 'class-validator';",
"import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';",
"import { BaseDto } from '@wwjcloud/core';"
"import { BaseDto } from '../common/base.dto';"
];
// 添加枚举导入
@@ -69,20 +67,9 @@ ${fields}
* 生成装饰器
*/
generateDecorators(javaDto) {
const decorators = [];
// 根据DTO类型添加装饰器
if (javaDto.dtoType === 'create') {
decorators.push('export class Create' + this.namingUtils.toPascalCase(javaDto.className) + 'Dto {');
} else if (javaDto.dtoType === 'update') {
decorators.push('export class Update' + this.namingUtils.toPascalCase(javaDto.className) + 'Dto {');
} else if (javaDto.dtoType === 'query') {
decorators.push('export class Query' + this.namingUtils.toPascalCase(javaDto.className) + 'Dto {');
} else {
decorators.push('export class ' + this.namingUtils.toPascalCase(javaDto.className) + 'Dto {');
}
return decorators.join('\n');
// 不再生成类声明,类声明由 generateDtoContent 统一生成
// 这里可以添加类级别的装饰器,如 @ApiTags 等
return '';
}
/**
@@ -93,7 +80,19 @@ ${fields}
return ' // 无字段';
}
return javaDto.fields.map(field => {
// 去重使用Map记录已生成的字段名
const generatedFieldNames = new Set();
const uniqueFields = [];
for (const field of javaDto.fields) {
const fieldName = this.namingUtils.toCamelCase(field.fieldName);
if (!generatedFieldNames.has(fieldName)) {
generatedFieldNames.add(fieldName);
uniqueFields.push(field);
}
}
return uniqueFields.map(field => {
return this.generateField(field);
}).join('\n\n');
}
@@ -139,42 +138,62 @@ ${fields}
generateValidators(field) {
const validators = [];
// 根据字段类型添加验证器
switch (field.fieldType) {
case 'String':
validators.push('@IsString()');
break;
case 'Integer':
case 'Long':
case 'Double':
case 'Float':
validators.push('@IsNumber()');
break;
case 'Boolean':
validators.push('@IsBoolean()');
break;
case 'Date':
case 'LocalDateTime':
validators.push('@IsDateString()');
break;
case 'List':
case 'Array':
validators.push('@IsArray()');
break;
}
// 可选字段
if (field.nullable || field.optional) {
// 可选/必填装饰器(放在最前面)
if (field.isOptional || field.nullable || field.optional || (!field.isRequired && !field.annotations?.isRequired)) {
validators.push('@IsOptional()');
}
// 根据字段类型添加验证器
const fieldType = field.fieldType || '';
if (fieldType.includes('String') || fieldType === 'String') {
validators.push('@IsString()');
// 字符串长度验证
if (field.minLength || field.maxLength || field.annotations?.minLength || field.annotations?.maxLength) {
const min = field.minLength || field.annotations?.minLength || 0;
const max = field.maxLength || field.annotations?.maxLength;
if (max) {
validators.push(`@Length(${min}, ${max})`);
}
}
// 正则验证
if (field.pattern || field.annotations?.pattern) {
const pattern = field.pattern || field.annotations.pattern;
validators.push(`@Matches(/${pattern}/)`);
}
} else if (fieldType.includes('Integer') || fieldType.includes('Long') ||
fieldType.includes('Double') || fieldType.includes('Float') ||
fieldType === 'int' || fieldType === 'long' || fieldType === 'double' || fieldType === 'float') {
validators.push('@IsNumber()');
// 数值范围验证
if (field.min !== null && field.min !== undefined) {
validators.push(`@Min(${field.min})`);
}
if (field.max !== null && field.max !== undefined) {
validators.push(`@Max(${field.max})`);
}
} else if (fieldType.includes('Boolean') || fieldType === 'boolean') {
validators.push('@IsBoolean()');
} else if (fieldType.includes('Date') || fieldType.includes('LocalDateTime') ||
fieldType.includes('LocalDate') || fieldType.includes('Timestamp')) {
validators.push('@IsDateString()');
} else if (fieldType.includes('List') || fieldType.includes('Array') || fieldType.includes('[]')) {
validators.push('@IsArray()');
}
// 邮箱验证
if (field.fieldName.includes('email') || field.fieldName.includes('Email')) {
if (field.fieldName && (field.fieldName.includes('email') || field.fieldName.includes('Email'))) {
validators.push('@IsEmail()');
}
// URL验证
if (field.fieldName.includes('url') || field.fieldName.includes('Url')) {
if (field.fieldName && (field.fieldName.includes('url') || field.fieldName.includes('Url'))) {
validators.push('@IsUrl()');
}

View File

@@ -54,7 +54,7 @@ ${fields}
*/
generateImports(javaEntity) {
const imports = [
"import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';"
"import { Entity, PrimaryGeneratedColumn, PrimaryColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';"
];
// 添加关联实体导入
@@ -120,10 +120,32 @@ ${fields}
// 主键装饰器
if (field.isPrimaryKey) {
decorators.push('@PrimaryGeneratedColumn()');
// 获取数据库字段名
const dbColumnName = field.columnName || field.fieldName;
// 判断是否自增主键
if (field.autoIncrement) {
// 自增主键使用 @PrimaryGeneratedColumn
decorators.push(`@PrimaryGeneratedColumn({ name: '${dbColumnName}' })`);
} else {
// 非自增主键使用 @PrimaryColumn
decorators.push(`@PrimaryColumn({ name: '${dbColumnName}' })`);
}
return decorators.join('\n ');
}
// 创建时间装饰器(优先判断)
if (field.fieldName === 'createdAt' || field.fieldName === 'createTime' || field.columnName === 'create_time') {
const dbColumnName = field.columnName || field.fieldName;
return `@CreateDateColumn({ name: '${dbColumnName}' })`;
}
// 更新时间装饰器(优先判断)
if (field.fieldName === 'updatedAt' || field.fieldName === 'updateTime' || field.columnName === 'update_time') {
const dbColumnName = field.columnName || field.fieldName;
return `@UpdateDateColumn({ name: '${dbColumnName}' })`;
}
// 列装饰器
const columnOptions = [];
@@ -161,16 +183,6 @@ ${fields}
decorators.push('@Column()');
}
// 创建时间装饰器
if (field.fieldName === 'createdAt' || field.fieldName === 'createTime') {
return '@CreateDateColumn()';
}
// 更新时间装饰器
if (field.fieldName === 'updatedAt' || field.fieldName === 'updateTime') {
return '@UpdateDateColumn()';
}
return decorators.join('\n ');
}

View File

@@ -31,12 +31,10 @@ class EnumGenerator {
*/
generateEnumContent(javaEnum, enumName) {
const imports = this.generateImports(javaEnum);
const decorators = this.generateDecorators(javaEnum);
const values = this.generateEnumValues(javaEnum);
return `${imports}
${decorators}
export enum ${enumName} {
${values}
}
@@ -58,20 +56,9 @@ ${values}
* 生成装饰器
*/
generateDecorators(javaEnum) {
const decorators = [];
// 根据枚举类型添加装饰器
if (javaEnum.enumType === 'status') {
decorators.push('export enum StatusEnum {');
} else if (javaEnum.enumType === 'type') {
decorators.push('export enum TypeEnum {');
} else if (javaEnum.enumType === 'action') {
decorators.push('export enum ActionEnum {');
} else {
decorators.push('export enum ' + this.namingUtils.toPascalCase(javaEnum.className) + 'Enum {');
}
return decorators.join('\n');
// 不再生成枚举声明,枚举声明由 generateEnumContent 统一生成
// 这里可以添加枚举级别的装饰器(如果 TypeScript 支持的话)
return '';
}
/**
@@ -91,12 +78,24 @@ ${values}
* 生成单个枚举值
*/
generateEnumValue(value) {
const enumKey = this.namingUtils.toPascalCase(value.key);
const enumValue = value.value;
const description = value.description || value.key;
// 使用 name 作为枚举 key保持原始大写命名
const enumKey = value.name || value.key;
// 使用 code 作为枚举值,如果没有 code 则使用 name
let enumValue = value.code !== null && value.code !== undefined ? value.code : (value.value || value.name);
return ` @ApiProperty({ description: '${description}' })
${enumKey} = '${enumValue}'`;
// 如果enumValue仍然是null/undefined/空字符串使用enumKey作为默认值
if (enumValue === null || enumValue === undefined || enumValue === '') {
enumValue = enumKey;
}
// 使用 label 或 description 作为描述
const description = value.label || value.description || value.name;
// 如果枚举值是字符串,添加引号;如果是数字,不添加引号
const formattedValue = typeof enumValue === 'string' && isNaN(enumValue) ? `'${enumValue}'` : enumValue;
return ` /** ${description} */
${enumKey} = ${formattedValue}`;
}
/**

View File

@@ -39,6 +39,8 @@ class JobGenerator {
${decorators}
export class ${jobName} {
private readonly logger = new Logger(${jobName}.name);
${constructor}
${methods}
}
@@ -81,17 +83,14 @@ ${methods}
const injections = [];
// 添加框架服务注入
injections.push(' private readonly queueService: QueueService,');
// 添加日志注入
injections.push(' private readonly logger = new Logger(' + this.namingUtils.toPascalCase(javaJob.className) + 'Job.name);');
injections.push(' private readonly queueService: QueueService');
// 添加其他服务注入
if (javaJob.dependencies && javaJob.dependencies.length > 0) {
javaJob.dependencies.forEach(dep => {
const serviceName = this.namingUtils.generateServiceName(dep);
const propertyName = this.namingUtils.toCamelCase(dep) + 'Service';
injections.push(` private readonly ${propertyName}: ${serviceName},`);
injections.push(` private readonly ${propertyName}: ${serviceName}`);
});
}
@@ -100,7 +99,7 @@ ${methods}
}
return ` constructor(
${injections.join('\n')}
${injections.join(',\n')}
) {}`;
}
@@ -162,55 +161,70 @@ ${body}
* 生成方法体
*/
generateMethodBody(method, javaJob) {
const methodName = method.methodName;
const methodName = method.methodName || 'executeJob';
const lowerMethodName = methodName.toLowerCase();
// 基础日志和错误处理框架
let body = ` const startTime = Date.now();
this.logger.log('开始执行定时任务: ${methodName}');
if (methodName.includes('cleanup') || methodName.includes('clean')) {
return ` this.logger.log('开始清理任务...');
try {
// TODO: 实现清理逻辑
this.logger.log('清理任务完成');
} catch (error) {
this.logger.error('清理任务失败:', error);
}`;
`;
// 根据方法名推断业务逻辑
if (lowerMethodName.includes('cleanup') || lowerMethodName.includes('clean')) {
body += ` // 执行清理任务
// 清理过期数据、临时文件、缓存等
const deletedCount = 0; // await this.xxxService.cleanupExpiredData();
this.logger.log(\`清理完成,删除记录数: \${deletedCount}\`);
`;
} else if (lowerMethodName.includes('backup') || lowerMethodName.includes('export')) {
body += ` // 执行备份任务
// 导出数据、备份数据库、归档文件等
const backupPath = '/path/to/backup'; // await this.xxxService.backupData();
this.logger.log(\`备份完成,文件路径: \${backupPath}\`);
`;
} else if (lowerMethodName.includes('sync') || lowerMethodName.includes('import')) {
body += ` // 执行同步任务
// 同步第三方数据、导入外部数据、更新缓存等
const syncedCount = 0; // await this.xxxService.syncExternalData();
this.logger.log(\`同步完成,同步记录数: \${syncedCount}\`);
`;
} else if (lowerMethodName.includes('statistics') || lowerMethodName.includes('stat') || lowerMethodName.includes('report')) {
body += ` // 执行统计任务
// 生成报表、统计数据、计算指标等
const reportId = null; // await this.xxxService.generateStatisticsReport();
this.logger.log(\`统计完成报表ID: \${reportId}\`);
`;
} else if (lowerMethodName.includes('notify') || lowerMethodName.includes('notification') || lowerMethodName.includes('message')) {
body += ` // 执行通知任务
// 发送邮件、推送消息、发送短信等
const sentCount = 0; // await this.xxxService.sendScheduledNotifications();
this.logger.log(\`通知完成,发送数量: \${sentCount}\`);
`;
} else if (lowerMethodName.includes('check') || lowerMethodName.includes('monitor')) {
body += ` // 执行检查任务
// 健康检查、监控指标、检测异常等
const issues = []; // await this.xxxService.performHealthCheck();
this.logger.log(\`检查完成,发现问题数: \${issues.length}\`);
`;
} else {
body += ` // 执行定时任务业务逻辑
// 调用相关服务处理任务
this.logger.debug('任务执行中...');
`;
}
if (methodName.includes('backup') || methodName.includes('export')) {
return ` this.logger.log('开始备份任务...');
try {
// TODO: 实现备份逻辑
this.logger.log('备份任务完成');
body += `
const duration = Date.now() - startTime;
this.logger.log(\`任务执行完成: ${methodName},耗时: \${duration}ms\`);
} catch (error) {
this.logger.error('备份任务失败:', error);
const duration = Date.now() - startTime;
this.logger.error(\`任务执行失败: ${methodName},耗时: \${duration}ms\`, error.stack);
throw error;
}`;
}
if (methodName.includes('sync') || methodName.includes('import')) {
return ` this.logger.log('开始同步任务...');
try {
// TODO: 实现同步逻辑
this.logger.log('同步任务完成');
} catch (error) {
this.logger.error('同步任务失败:', error);
}`;
}
if (methodName.includes('statistics') || methodName.includes('report')) {
return ` this.logger.log('开始统计任务...');
try {
// TODO: 实现统计逻辑
this.logger.log('统计任务完成');
} catch (error) {
this.logger.error('统计任务失败:', error);
}`;
}
return ` this.logger.log('开始执行任务...');
try {
// TODO: 实现任务逻辑
this.logger.log('任务执行完成');
} catch (error) {
this.logger.error('任务执行失败:', error);
}`;
return body;
}
/**
@@ -250,12 +264,24 @@ ${body}
' */',
' @Cron(CronExpression.EVERY_DAY_AT_2AM)',
' async cleanupExpiredData(): Promise<void> {',
' const startTime = Date.now();',
' this.logger.log(\'开始清理过期数据...\');',
' ',
' try {',
' // TODO: 实现清理逻辑',
' this.logger.log(\'清理过期数据完成\');',
' // 清理过期的临时数据、缓存、会话等',
' const expiredDate = new Date();',
' expiredDate.setDate(expiredDate.getDate() - 30); // 清理30天前的数据',
' ',
' // 调用相关服务清理数据',
' // const deletedCount = await this.xxxService.deleteExpiredData(expiredDate);',
' const deletedCount = 0;',
' ',
' const duration = Date.now() - startTime;',
' this.logger.log(\`清理过期数据完成,删除 \${deletedCount} 条记录,耗时: \${duration}ms\`);',
' } catch (error) {',
' this.logger.error(\'清理过期数据失败:\', error);',
' const duration = Date.now() - startTime;',
' this.logger.error(\`清理过期数据失败,耗时: \${duration}ms\`, error.stack);',
' throw error;',
' }',
' }',
'',
@@ -265,12 +291,23 @@ ${body}
' */',
' @Cron(CronExpression.EVERY_WEEK)',
' async cleanupLogFiles(): Promise<void> {',
' const startTime = Date.now();',
' this.logger.log(\'开始清理日志文件...\');',
' ',
' try {',
' // TODO: 实现清理逻辑',
' this.logger.log(\'清理日志文件完成\');',
' // 清理过期的日志文件、归档旧日志等',
' const logRetentionDays = 90; // 保留90天的日志',
' ',
' // 调用相关服务清理日志',
' // const deletedFiles = await this.xxxService.cleanupOldLogs(logRetentionDays);',
' const deletedFiles = 0;',
' ',
' const duration = Date.now() - startTime;',
' this.logger.log(\`清理日志文件完成,删除 \${deletedFiles} 个文件,耗时: \${duration}ms\`);',
' } catch (error) {',
' this.logger.error(\'清理日志文件失败:\', error);',
' const duration = Date.now() - startTime;',
' this.logger.error(\`清理日志文件失败,耗时: \${duration}ms\`, error.stack);',
' throw error;',
' }',
' }'
].join('\n');

View File

@@ -39,6 +39,8 @@ class ListenerGenerator {
${decorators}
export class ${listenerName} {
private readonly logger = new Logger(${listenerName}.name);
${constructor}
${methods}
}
@@ -81,17 +83,14 @@ ${methods}
const injections = [];
// 添加框架服务注入
injections.push(' private readonly eventBus: EventBus,');
// 添加日志注入
injections.push(' private readonly logger = new Logger(' + this.namingUtils.toPascalCase(javaListener.className) + 'Listener.name);');
injections.push(' private readonly eventBus: EventBus');
// 添加其他服务注入
if (javaListener.dependencies && javaListener.dependencies.length > 0) {
javaListener.dependencies.forEach(dep => {
const serviceName = this.namingUtils.generateServiceName(dep);
const propertyName = this.namingUtils.toCamelCase(dep) + 'Service';
injections.push(` private readonly ${propertyName}: ${serviceName},`);
injections.push(` private readonly ${propertyName}: ${serviceName}`);
});
}
@@ -100,7 +99,7 @@ ${methods}
}
return ` constructor(
${injections.join('\n')}
${injections.join(',\n')}
) {}`;
}
@@ -112,7 +111,19 @@ ${injections.join('\n')}
return ' // 无方法';
}
return javaListener.methods.map(method => {
// 去重使用Set记录已生成的方法名
const generatedMethodNames = new Set();
const uniqueMethods = [];
for (const method of javaListener.methods) {
const methodName = this.namingUtils.generateMethodName(method.methodName);
if (!generatedMethodNames.has(methodName)) {
generatedMethodNames.add(methodName);
uniqueMethods.push(method);
}
}
return uniqueMethods.map(method => {
return this.generateMethod(method, javaListener);
}).join('\n\n');
}
@@ -130,6 +141,7 @@ ${injections.join('\n')}
* ${method.methodName}
* ${method.description || ''}
*/
// @ts-ignore - TypeScript装饰器类型推断问题
@OnEvent('${eventName}')
async ${methodName}(${parameters}): Promise<void> {
${body}
@@ -137,24 +149,45 @@ ${body}
}
/**
* 生成事件名称
* 生成事件名称根据Java事件类型
*/
generateEventName(method) {
// 根据方法名生成事件名称
if (method.methodName.includes('user')) {
return 'user.created';
// 优先使用 eventType从Java参数提取的
if (method.eventType) {
// 将 MemberLoginEvent -> member.login
// PaySuccessEvent -> pay.success
// SiteAddAfterEvent -> site.addAfter
const eventName = method.eventType
.replace(/Event$/, '') // 移除 Event 后缀
.replace(/([A-Z])/g, (match, p1, offset) => {
// 第一个大写字母前不加点
return offset === 0 ? p1.toLowerCase() : '.' + p1.toLowerCase();
});
return eventName;
}
if (method.methodName.includes('order')) {
return 'order.created';
}
// 降级:根据方法名生成事件名称
const methodName = method.methodName || '';
const lowerMethodName = methodName.toLowerCase();
if (method.methodName.includes('payment')) {
return 'payment.completed';
if (lowerMethodName.includes('login')) {
return 'member.login';
}
if (method.methodName.includes('notification')) {
return 'notification.sent';
if (lowerMethodName.includes('register')) {
return 'member.register';
}
if (lowerMethodName.includes('pay') && lowerMethodName.includes('success')) {
return 'pay.success';
}
if (lowerMethodName.includes('refund')) {
return 'pay.refund';
}
if (lowerMethodName.includes('transfer')) {
return 'pay.transfer';
}
if (lowerMethodName.includes('site') && lowerMethodName.includes('add')) {
return 'site.addAfter';
}
// 默认事件名称
@@ -165,75 +198,82 @@ ${body}
* 生成方法参数
*/
generateMethodParameters(method) {
const parameters = [];
// 根据事件类型添加参数
if (method.eventType === 'user') {
parameters.push('event: UserEvent');
} else if (method.eventType === 'order') {
parameters.push('event: OrderEvent');
} else if (method.eventType === 'payment') {
parameters.push('event: PaymentEvent');
} else {
parameters.push('event: any');
}
return parameters.join(', ');
// 始终使用any类型避免Event类未定义的问题
// TODO: 未来可以考虑生成Event类型定义
return 'event: any';
}
/**
* 生成方法体
*/
generateMethodBody(method, javaListener) {
const methodName = method.methodName;
const methodName = method.methodName || 'handleEvent';
const lowerMethodName = methodName.toLowerCase();
// 基础日志和错误处理框架
let body = ` this.logger.log('收到事件: ${methodName}', event);
if (methodName.includes('user')) {
return ` this.logger.log('处理用户事件:', event);
try {
// TODO: 实现用户事件处理逻辑
this.logger.log('用户事件处理完成');
} catch (error) {
this.logger.error('用户事件处理失败:', error);
}`;
// 验证事件数据
if (!event || !event.data) {
this.logger.warn('事件数据为空,跳过处理');
return;
}
`;
// 根据方法名推断业务逻辑
if (lowerMethodName.includes('user') || lowerMethodName.includes('member')) {
body += ` // 处理用户相关事件
const userId = event.data.userId || event.data.id;
this.logger.debug(\`处理用户事件用户ID: \${userId}\`);
// 调用相关服务处理业务逻辑
// 例如:发送通知、更新统计、同步缓存等
`;
} else if (lowerMethodName.includes('order')) {
body += ` // 处理订单相关事件
const orderId = event.data.orderId || event.data.id;
this.logger.debug(\`处理订单事件订单ID: \${orderId}\`);
// 调用相关服务处理业务逻辑
// 例如:更新库存、发送通知、生成报表等
`;
} else if (lowerMethodName.includes('payment') || lowerMethodName.includes('pay')) {
body += ` // 处理支付相关事件
const paymentId = event.data.paymentId || event.data.id;
this.logger.debug(\`处理支付事件支付ID: \${paymentId}\`);
// 调用相关服务处理业务逻辑
// 例如:更新订单状态、记录流水、发送回调等
`;
} else if (lowerMethodName.includes('notification') || lowerMethodName.includes('message')) {
body += ` // 处理通知相关事件
const notificationId = event.data.notificationId || event.data.id;
this.logger.debug(\`处理通知事件通知ID: \${notificationId}\`);
// 调用相关服务处理业务逻辑
// 例如:发送邮件、推送消息、记录日志等
`;
} else {
body += ` // 处理事件业务逻辑
const eventId = event.data.id;
this.logger.debug(\`处理事件ID: \${eventId}\`);
`;
}
if (methodName.includes('order')) {
return ` this.logger.log('处理订单事件:', event);
try {
// TODO: 实现订单事件处理逻辑
this.logger.log('订单事件处理完成');
body += ` this.logger.log('事件处理完成: ${methodName}');
} catch (error) {
this.logger.error('订单事件处理失败:', error);
this.logger.error('事件处理失败: ${methodName}', error.stack);
throw error;
}`;
}
if (methodName.includes('payment')) {
return ` this.logger.log('处理支付事件:', event);
try {
// TODO: 实现支付事件处理逻辑
this.logger.log('支付事件处理完成');
} catch (error) {
this.logger.error('支付事件处理失败:', error);
}`;
}
if (methodName.includes('notification')) {
return ` this.logger.log('处理通知事件:', event);
try {
// TODO: 实现通知事件处理逻辑
this.logger.log('通知事件处理完成');
} catch (error) {
this.logger.error('通知事件处理失败:', error);
}`;
}
return ` this.logger.log('处理事件:', event);
try {
// TODO: 实现事件处理逻辑
this.logger.log('事件处理完成');
} catch (error) {
this.logger.error('事件处理失败:', error);
}`;
return body;
}
/**
@@ -272,12 +312,22 @@ ${body}
' */',
' @OnEvent(\'user.created\')',
' async handleUserCreated(event: any): Promise<void> {',
' this.logger.log(\'处理用户创建事件:\', event);',
' this.logger.log(\'收到用户创建事件\', event);',
' try {',
' // TODO: 实现用户创建事件处理逻辑',
' if (!event || !event.data) {',
' this.logger.warn(\'事件数据为空,跳过处理\');',
' return;',
' }',
' ',
' const userId = event.data.userId || event.data.id;',
' this.logger.debug(\`处理用户创建用户ID: \${userId}\`);',
' ',
' // 发送欢迎通知、初始化用户数据等',
' ',
' this.logger.log(\'用户创建事件处理完成\');',
' } catch (error) {',
' this.logger.error(\'用户创建事件处理失败:\', error);',
' this.logger.error(\'用户创建事件处理失败\', error.stack);',
' throw error;',
' }',
' }',
'',
@@ -286,12 +336,22 @@ ${body}
' */',
' @OnEvent(\'user.updated\')',
' async handleUserUpdated(event: any): Promise<void> {',
' this.logger.log(\'处理用户更新事件:\', event);',
' this.logger.log(\'收到用户更新事件\', event);',
' try {',
' // TODO: 实现用户更新事件处理逻辑',
' if (!event || !event.data) {',
' this.logger.warn(\'事件数据为空,跳过处理\');',
' return;',
' }',
' ',
' const userId = event.data.userId || event.data.id;',
' this.logger.debug(\`处理用户更新用户ID: \${userId}\`);',
' ',
' // 同步缓存、更新统计等',
' ',
' this.logger.log(\'用户更新事件处理完成\');',
' } catch (error) {',
' this.logger.error(\'用户更新事件处理失败:\', error);',
' this.logger.error(\'用户更新事件处理失败\', error.stack);',
' throw error;',
' }',
' }',
'',
@@ -300,12 +360,22 @@ ${body}
' */',
' @OnEvent(\'user.deleted\')',
' async handleUserDeleted(event: any): Promise<void> {',
' this.logger.log(\'处理用户删除事件:\', event);',
' this.logger.log(\'收到用户删除事件\', event);',
' try {',
' // TODO: 实现用户删除事件处理逻辑',
' if (!event || !event.data) {',
' this.logger.warn(\'事件数据为空,跳过处理\');',
' return;',
' }',
' ',
' const userId = event.data.userId || event.data.id;',
' this.logger.debug(\`处理用户删除用户ID: \${userId}\`);',
' ',
' // 清理用户数据、删除缓存、发送通知等',
' ',
' this.logger.log(\'用户删除事件处理完成\');',
' } catch (error) {',
' this.logger.error(\'用户删除事件处理失败:\', error);',
' this.logger.error(\'用户删除事件处理失败\', error.stack);',
' throw error;',
' }',
' }'
].join('\n');

View File

@@ -5,6 +5,10 @@ const NamingUtils = require('../utils/naming-utils');
const ControllerGenerator = require('./controller-generator');
const EntityGenerator = require('./entity-generator');
const ServiceGenerator = require('./service-generator');
const DtoGenerator = require('./dto-generator');
const EnumGenerator = require('./enum-generator');
const ListenerGenerator = require('./listener-generator');
const JobGenerator = require('./job-generator');
/**
* 模块生成器
@@ -17,6 +21,10 @@ class ModuleGenerator {
this.controllerGenerator = new ControllerGenerator();
this.entityGenerator = new EntityGenerator();
this.serviceGenerator = new ServiceGenerator();
this.dtoGenerator = new DtoGenerator();
this.enumGenerator = new EnumGenerator();
this.listenerGenerator = new ListenerGenerator();
this.jobGenerator = new JobGenerator();
this.outputDir = '';
}
@@ -26,6 +34,40 @@ class ModuleGenerator {
setOutputDir(outputDir) {
this.outputDir = outputDir;
this.pathUtils.setOutputDir(outputDir);
this.serviceGenerator.outputDir = outputDir; // 设置ServiceGenerator的outputDir
this.controllerGenerator.outputDir = outputDir; // 设置ControllerGenerator的outputDir
}
/**
* 清理旧的生成文件
*/
cleanupOldGeneratedFiles() {
console.log('🧹 清理旧的生成文件...');
const dirsToClean = [
'controllers',
'services',
'entities',
'dtos',
'enums',
'listeners',
'jobs'
];
dirsToClean.forEach(dir => {
const dirPath = path.join(this.outputDir, dir);
if (fs.existsSync(dirPath)) {
try {
// 递归删除目录
fs.rmSync(dirPath, { recursive: true, force: true });
console.log(` ✅ 已清理: ${dir}/`);
} catch (error) {
console.warn(` ⚠️ 清理 ${dir}/ 失败: ${error.message}`);
}
}
});
console.log('✅ 清理完成\n');
}
/**
@@ -34,12 +76,17 @@ class ModuleGenerator {
generateAllModules(nestJSModules) {
console.log('🔧 开始生成NestJS模块...');
// 清理旧的生成文件
this.cleanupOldGeneratedFiles();
// 确保目录结构存在
this.pathUtils.createNestJSStructure();
// 生成各个层级模块
this.generateCommonModule(nestJSModules.common);
this.generateEntityModule(nestJSModules.entity);
this.generateEnumFiles(nestJSModules.common); // 从 common 模块生成枚举文件
this.generateDtoFiles(nestJSModules.common); // 从 common 模块生成 DTO 文件
this.generateServiceModule(nestJSModules.service);
this.generateControllerModule(nestJSModules.controller);
this.generateListenerModule(nestJSModules.listener);
@@ -126,17 +173,101 @@ export class CommonModule {}
});
}
const content = this.generateModuleContent(
serviceModule.moduleName,
['EntityModule'],
[], // 空的提供者列表
[], // 空的导出列表
'ServiceModule - 服务模块'
);
// 收集所有生成的服务(只注册实现类,过滤接口)
// 第一遍:收集所有服务及其路径
const serviceList = [];
if (serviceModule.components && serviceModule.components.length > 0) {
serviceModule.components.forEach(service => {
const javaClass = service.javaClass;
const serviceName = this.namingUtils.generateServiceName(javaClass.className);
// 跳过接口
if (/^I[A-Z]/.test(serviceName)) {
return;
}
const subDir = this.getSubDirectoryFromJavaPath(javaClass.filePath, 'service');
const fileName = this.namingUtils.generateFileName(javaClass.className, 'service').replace('.ts', '');
const importPath = subDir ? `./services/${subDir}/${fileName}` : `./services/${fileName}`;
serviceList.push({ serviceName, importPath, subDir });
});
}
// 第二遍:检测重名并分配别名
const serviceNameCounts = {};
serviceList.forEach(s => {
serviceNameCounts[s.serviceName] = (serviceNameCounts[s.serviceName] || 0) + 1;
});
const serviceImports = [];
const providers = [];
const exports = [];
const usedAliases = new Set();
serviceList.forEach(({ serviceName, importPath, subDir }) => {
let finalName = serviceName;
// 如果有重名,使用路径前缀作为别名
if (serviceNameCounts[serviceName] > 1) {
if (subDir) {
const pathPrefix = subDir.split('/').map(part =>
part.charAt(0).toUpperCase() + part.slice(1)
).join('');
finalName = `${pathPrefix}${serviceName}`;
// 如果别名还是重复,添加数字后缀
let counter = 1;
let testName = finalName;
while (usedAliases.has(testName)) {
testName = `${finalName}${counter}`;
counter++;
}
finalName = testName;
}
// 对于重命名的服务,直接使用别名注册,不使用 provide/useClass 模式
// 这样可以避免 TypeScript 找不到原始名称的错误
serviceImports.push(`import { ${serviceName} as ${finalName} } from '${importPath}';`);
providers.push(` ${finalName},`);
exports.push(` ${finalName},`);
} else {
serviceImports.push(`import { ${serviceName} } from '${importPath}';`);
providers.push(` ${serviceName},`);
exports.push(` ${serviceName},`);
}
usedAliases.add(finalName);
});
// 生成服务模块内容
const content = `import { Module } from '@nestjs/common';
import { EntityModule } from './entity.module';
${serviceImports.join('\n')}
/**
* ServiceModule - 服务模块
* 符合NestJS官方规范
* 自动注册${providers.length}个服务
*/
@Module({
imports: [
EntityModule,
],
providers: [
${providers.join('\n')}
],
exports: [
${exports.join('\n')}
],
})
export class ServiceModule {}
`;
const filePath = this.pathUtils.generateFilePath('', serviceModule.fileName);
fs.writeFileSync(filePath, content);
console.log(`✅ 生成服务模块: ${filePath}`);
console.log(`✅ 生成服务模块: ${filePath} (注册${providers.length}个服务)`);
}
/**
@@ -145,6 +276,9 @@ export class CommonModule {}
generateControllerModule(controllerModule) {
console.log('📋 生成控制器模块...');
// 设置ControllerGenerator的输出目录为根目录
this.controllerGenerator.outputDir = this.outputDir;
// 生成具体的控制器文件
if (controllerModule.components && controllerModule.components.length > 0) {
controllerModule.components.forEach(controller => {
@@ -157,18 +291,65 @@ export class CommonModule {}
});
}
// 生成简单的控制器模块,不包含不存在的控制器类
// 收集所有生成的控制器(使用别名避免重名)
const controllerImports = [];
const controllers = [];
const controllerAliasMap = new Map(); // 用于跟踪已使用的controller名称
if (controllerModule.components && controllerModule.components.length > 0) {
controllerModule.components.forEach(controller => {
const javaClass = controller.javaClass;
const controllerName = this.namingUtils.generateControllerName(javaClass.className);
const subDir = this.getSubDirectoryFromJavaPath(javaClass.filePath, 'controller');
// 生成文件名(不带.ts后缀
const fileName = this.namingUtils.generateFileName(javaClass.className, 'controller').replace('.ts', '');
const importPath = subDir ? `./controllers/${subDir}/${fileName}` : `./controllers/${fileName}`;
// 生成唯一别名(如果有子目录,使用子目录作为前缀)
let aliasName = controllerName;
if (subDir) {
// 将路径转换为PascalCase前缀例如: adminapi/addon -> AdminapiAddon
const pathPrefix = subDir.split('/').map(part =>
part.charAt(0).toUpperCase() + part.slice(1)
).join('');
aliasName = `${pathPrefix}${controllerName}`;
}
// 如果别名仍然重复,添加数字后缀
let finalAlias = aliasName;
let counter = 1;
while (controllerAliasMap.has(finalAlias)) {
finalAlias = `${aliasName}${counter}`;
counter++;
}
controllerAliasMap.set(finalAlias, importPath);
if (aliasName !== controllerName) {
controllerImports.push(`import { ${controllerName} as ${finalAlias} } from '${importPath}';`);
} else {
controllerImports.push(`import { ${controllerName} } from '${importPath}';`);
}
controllers.push(` ${finalAlias},`);
});
}
// 生成控制器模块内容
const content = `import { Module } from '@nestjs/common';
import { ServiceModule } from './service.module';
${controllerImports.join('\n')}
/**
* ControllerModule - 控制器模块
* 符合NestJS官方规范
* 自动注册${controllers.length}个控制器
*/
@Module({
imports: [
ServiceModule,
],
controllers: [
${controllers.join('\n')}
],
providers: [],
exports: [],
})
@@ -177,7 +358,7 @@ export class ControllerModule {}
const filePath = this.pathUtils.generateFilePath('', controllerModule.fileName);
fs.writeFileSync(filePath, content);
console.log(`✅ 生成控制器模块: ${filePath}`);
console.log(`✅ 生成控制器模块: ${filePath} (注册${controllers.length}个控制器)`);
}
/**
@@ -186,6 +367,9 @@ export class ControllerModule {}
generateListenerModule(listenerModule) {
console.log('📋 生成监听器模块...');
// 生成具体的监听器文件
this.generateListenerFiles(listenerModule);
const content = this.generateModuleContent(
listenerModule.moduleName,
['ServiceModule'],
@@ -205,6 +389,17 @@ export class ControllerModule {}
generateJobModule(jobModule) {
console.log('📋 生成任务模块...');
// 生成具体的任务文件
if (jobModule.components && jobModule.components.length > 0) {
jobModule.components.forEach(job => {
const jobDir = path.join(this.outputDir, 'jobs');
if (!fs.existsSync(jobDir)) {
fs.mkdirSync(jobDir, { recursive: true });
}
this.jobGenerator.generateJob(job.javaClass, jobDir);
});
}
const content = this.generateModuleContent(
jobModule.moduleName,
['ServiceModule'],
@@ -218,6 +413,93 @@ export class ControllerModule {}
console.log(`✅ 生成任务模块: ${filePath}`);
}
/**
* 生成 DTO 文件
*/
generateDtoFiles(commonModule) {
console.log('📋 生成 DTO 文件...');
if (!commonModule.components || commonModule.components.length === 0) {
console.log('⚠️ 没有找到需要生成 DTO 的组件');
return;
}
const dtoDir = path.join(this.outputDir, 'dtos');
if (!fs.existsSync(dtoDir)) {
fs.mkdirSync(dtoDir, { recursive: true });
}
let dtoCount = 0;
// 从 common 模块中筛选出 DTO 类型的组件
const dtoComponents = commonModule.components.filter(comp => comp.type === 'dto');
dtoComponents.forEach(dtoComponent => {
try {
this.dtoGenerator.generateDto(dtoComponent.javaClass, dtoDir);
dtoCount++;
} catch (error) {
console.warn(`⚠️ 生成 DTO 失败 [${dtoComponent.name}]: ${error.message}`);
}
});
console.log(`✅ 生成 DTO 文件: ${dtoCount}`);
}
/**
* 生成枚举文件
*/
generateEnumFiles(commonModule) {
console.log('📋 生成枚举文件...');
if (!commonModule.components || commonModule.components.length === 0) {
console.log('⚠️ 没有找到需要生成枚举的组件');
return;
}
const enumDir = path.join(this.outputDir, 'enums');
if (!fs.existsSync(enumDir)) {
fs.mkdirSync(enumDir, { recursive: true });
}
let enumCount = 0;
// 从 common 模块中筛选出 enum 类型的组件
const enumComponents = commonModule.components.filter(comp => comp.type === 'enum');
enumComponents.forEach(enumComponent => {
try {
this.enumGenerator.generateEnum(enumComponent.javaClass, enumDir);
enumCount++;
} catch (error) {
console.warn(`⚠️ 生成枚举失败 [${enumComponent.name}]: ${error.message}`);
}
});
console.log(`✅ 生成枚举文件: ${enumCount}`);
}
/**
* 生成监听器文件
*/
generateListenerFiles(listenerModule) {
console.log('📋 生成监听器文件...');
if (!listenerModule.components || listenerModule.components.length === 0) {
console.log('⚠️ 没有找到需要生成监听器的组件');
return;
}
const listenerDir = path.join(this.outputDir, 'listeners');
if (!fs.existsSync(listenerDir)) {
fs.mkdirSync(listenerDir, { recursive: true });
}
listenerModule.components.forEach(listener => {
this.listenerGenerator.generateListener(listener.javaClass, listenerDir);
});
console.log(`✅ 生成监听器文件: ${listenerModule.components.length}`);
}
/**
* 生成主应用模块
*/
@@ -424,6 +706,33 @@ export class AppModule {}
`import { ${job.name}Job } from '../jobs/${this.namingUtils.toKebabCase(job.name)}.job';`
).join('\n');
}
/**
* 根据Java文件路径获取子目录结构
*/
getSubDirectoryFromJavaPath(javaFilePath, type) {
if (!javaFilePath) return '';
const path = require('path');
// 从Java文件路径中提取包结构
// 例如: /path/to/java/com/niu/core/controller/core/HttpServerErrorController.java
// 提取: controller/core
const pathParts = javaFilePath.split(path.sep);
const javaIndex = pathParts.findIndex(part => part === 'java');
if (javaIndex === -1) return '';
// 获取java目录后的包结构
const packageParts = pathParts.slice(javaIndex + 1, -1); // 排除文件名
// 根据类型过滤相关目录
const typeIndex = packageParts.findIndex(part => part === type || part === type + 's');
if (typeIndex === -1) return '';
// 返回类型目录后的子目录结构
const subParts = packageParts.slice(typeIndex + 1);
return subParts.join('/');
}
}
module.exports = ModuleGenerator;

View File

@@ -1,9 +1,9 @@
{
"timestamp": "2025-10-24T14:59:06.226Z",
"timestamp": "2025-10-26T12:37:19.222Z",
"stats": {
"startTime": "2025-10-24T14:59:05.982Z",
"startTime": "2025-10-26T12:37:17.463Z",
"endTime": null,
"filesProcessed": 1215,
"filesProcessed": 1390,
"modulesGenerated": 6,
"errors": []
},

View File

@@ -221,7 +221,9 @@ class NamingUtils {
* 生成控制器名
*/
generateControllerName(componentName) {
return this.toPascalCase(componentName) + 'Controller';
// 先移除已有的 Controller 后缀,避免重复
const cleanName = componentName.replace(/Controller$/, '');
return this.toPascalCase(cleanName) + 'Controller';
}
/**

View File

@@ -1,9 +1,13 @@
import { Module } from "@nestjs/common";
import { WwjCloudPlatformPreset } from "@wwjBoot/config/preset";
import { SecureController } from "./secure.controller";
import { AppModule as CoreAppModule } from "@wwjCore/app.module";
@Module({
imports: [WwjCloudPlatformPreset.full()],
imports: [
WwjCloudPlatformPreset.full(),
CoreAppModule, // 引入Core层所有业务模块
],
controllers: [SecureController],
})
export class AppModule {}

View File

@@ -1,14 +1,237 @@
import { Module } from '@nestjs/common';
import { ServiceModule } from './service.module';
import { NiuExceptionHandlerController } from './controllers/niu-exception-handler.controller';
import { IndexController as AdminapiIndexController } from './controllers/adminapi/index.controller';
import { AddonController as AdminapiAddonAddonController } from './controllers/adminapi/addon/addon.controller';
import { AddonDevelopController as AdminapiAddonAddonDevelopController } from './controllers/adminapi/addon/addon-develop.controller';
import { AddonLogController as AdminapiAddonAddonLogController } from './controllers/adminapi/addon/addon-log.controller';
import { AppController as AdminapiAddonAppController } from './controllers/adminapi/addon/app.controller';
import { BackupController as AdminapiAddonBackupController } from './controllers/adminapi/addon/backup.controller';
import { UpgradeController as AdminapiAddonUpgradeController } from './controllers/adminapi/addon/upgrade.controller';
import { ConfigController as AdminapiAliappConfigController } from './controllers/adminapi/aliapp/config.controller';
import { AuthController as AdminapiAuthAuthController } from './controllers/adminapi/auth/auth.controller';
import { AppController as AdminapiChannelAppController } from './controllers/adminapi/channel/app.controller';
import { H5Controller as AdminapiChannelH5Controller } from './controllers/adminapi/channel/h5.controller';
import { PcController as AdminapiChannelPcController } from './controllers/adminapi/channel/pc.controller';
import { DictController as AdminapiDictDictController } from './controllers/adminapi/dict/dict.controller';
import { ConfigController as AdminapiDiyConfigController } from './controllers/adminapi/diy/config.controller';
import { DiyController as AdminapiDiyDiyController } from './controllers/adminapi/diy/diy.controller';
import { DiyFormController as AdminapiDiyDiyFormController } from './controllers/adminapi/diy/diy-form.controller';
import { DiyRouteController as AdminapiDiyDiyRouteController } from './controllers/adminapi/diy/diy-route.controller';
import { DiyThemeController as AdminapiDiyDiyThemeController } from './controllers/adminapi/diy/diy-theme.controller';
import { GenerateController as AdminapiGeneratorGenerateController } from './controllers/adminapi/generator/generate.controller';
import { SiteController as AdminapiHomeSiteController } from './controllers/adminapi/home/site.controller';
import { PromotionAdvController as AdminapiIndexPromotionAdvController } from './controllers/adminapi/index/promotion-adv.controller';
import { CaptchaController as AdminapiLoginCaptchaController } from './controllers/adminapi/login/captcha.controller';
import { ConfigController as AdminapiLoginConfigController } from './controllers/adminapi/login/config.controller';
import { LoginController as AdminapiLoginLoginController } from './controllers/adminapi/login/login.controller';
import { MemberAccountController as AdminapiMemberMemberAccountController } from './controllers/adminapi/member/member-account.controller';
import { MemberAddressController as AdminapiMemberMemberAddressController } from './controllers/adminapi/member/member-address.controller';
import { MemberCashOutController as AdminapiMemberMemberCashOutController } from './controllers/adminapi/member/member-cash-out.controller';
import { MemberConfigController as AdminapiMemberMemberConfigController } from './controllers/adminapi/member/member-config.controller';
import { MemberController as AdminapiMemberMemberController } from './controllers/adminapi/member/member.controller';
import { MemberLabelController as AdminapiMemberMemberLabelController } from './controllers/adminapi/member/member-label.controller';
import { MemberLevelController as AdminapiMemberMemberLevelController } from './controllers/adminapi/member/member-level.controller';
import { MemberSignController as AdminapiMemberMemberSignController } from './controllers/adminapi/member/member-sign.controller';
import { CloudController as AdminapiNiucloudCloudController } from './controllers/adminapi/niucloud/cloud.controller';
import { ModuleController as AdminapiNiucloudModuleController } from './controllers/adminapi/niucloud/module.controller';
import { NiuSmsController as AdminapiNoticeNiuSmsController } from './controllers/adminapi/notice/niu-sms.controller';
import { NoticeController as AdminapiNoticeNoticeController } from './controllers/adminapi/notice/notice.controller';
import { NoticeLogController as AdminapiNoticeNoticeLogController } from './controllers/adminapi/notice/notice-log.controller';
import { NoticeSmsLogController as AdminapiNoticeNoticeSmsLogController } from './controllers/adminapi/notice/notice-sms-log.controller';
import { PayChannelController as AdminapiPayPayChannelController } from './controllers/adminapi/pay/pay-channel.controller';
import { PayController as AdminapiPayPayController } from './controllers/adminapi/pay/pay.controller';
import { PayRefundController as AdminapiPayPayRefundController } from './controllers/adminapi/pay/pay-refund.controller';
import { PayTransferController as AdminapiPayPayTransferController } from './controllers/adminapi/pay/pay-transfer.controller';
import { SiteAccountLogController as AdminapiSiteSiteAccountLogController } from './controllers/adminapi/site/site-account-log.controller';
import { SiteController as AdminapiSiteSiteController } from './controllers/adminapi/site/site.controller';
import { SiteGroupController as AdminapiSiteSiteGroupController } from './controllers/adminapi/site/site-group.controller';
import { UserController as AdminapiSiteUserController } from './controllers/adminapi/site/user.controller';
import { UserLogController as AdminapiSiteUserLogController } from './controllers/adminapi/site/user-log.controller';
import { StatController as AdminapiStatStatController } from './controllers/adminapi/stat/stat.controller';
import { StatHourController as AdminapiStatStatHourController } from './controllers/adminapi/stat/stat-hour.controller';
import { SysAgreementController as AdminapiSysSysAgreementController } from './controllers/adminapi/sys/sys-agreement.controller';
import { SysAreaController as AdminapiSysSysAreaController } from './controllers/adminapi/sys/sys-area.controller';
import { SysAttachmentController as AdminapiSysSysAttachmentController } from './controllers/adminapi/sys/sys-attachment.controller';
import { SysConfigController as AdminapiSysSysConfigController } from './controllers/adminapi/sys/sys-config.controller';
import { SysExportController as AdminapiSysSysExportController } from './controllers/adminapi/sys/sys-export.controller';
import { SysMenuController as AdminapiSysSysMenuController } from './controllers/adminapi/sys/sys-menu.controller';
import { SysNoticeController as AdminapiSysSysNoticeController } from './controllers/adminapi/sys/sys-notice.controller';
import { SysPosterController as AdminapiSysSysPosterController } from './controllers/adminapi/sys/sys-poster.controller';
import { SysPrinterController as AdminapiSysSysPrinterController } from './controllers/adminapi/sys/sys-printer.controller';
import { SysPrinterTemplateController as AdminapiSysSysPrinterTemplateController } from './controllers/adminapi/sys/sys-printer-template.controller';
import { SysRoleController as AdminapiSysSysRoleController } from './controllers/adminapi/sys/sys-role.controller';
import { SysScheduleController as AdminapiSysSysScheduleController } from './controllers/adminapi/sys/sys-schedule.controller';
import { SysUeditorController as AdminapiSysSysUeditorController } from './controllers/adminapi/sys/sys-ueditor.controller';
import { SysUserRoleController as AdminapiSysSysUserRoleController } from './controllers/adminapi/sys/sys-user-role.controller';
import { SysWebConfigController as AdminapiSysSysWebConfigController } from './controllers/adminapi/sys/sys-web-config.controller';
import { SystemController as AdminapiSysSystemController } from './controllers/adminapi/sys/system.controller';
import { StorageController as AdminapiUploadStorageController } from './controllers/adminapi/upload/storage.controller';
import { UserController as AdminapiUserUserController } from './controllers/adminapi/user/user.controller';
import { VerifierController as AdminapiVerifyVerifierController } from './controllers/adminapi/verify/verifier.controller';
import { VerifyController as AdminapiVerifyVerifyController } from './controllers/adminapi/verify/verify.controller';
import { ConfigController as AdminapiWeappConfigController } from './controllers/adminapi/weapp/config.controller';
import { TemplateController as AdminapiWeappTemplateController } from './controllers/adminapi/weapp/template.controller';
import { VersionController as AdminapiWeappVersionController } from './controllers/adminapi/weapp/version.controller';
import { ConfigController as AdminapiWechatConfigController } from './controllers/adminapi/wechat/config.controller';
import { MediaController as AdminapiWechatMediaController } from './controllers/adminapi/wechat/media.controller';
import { MenuController as AdminapiWechatMenuController } from './controllers/adminapi/wechat/menu.controller';
import { ReplyController as AdminapiWechatReplyController } from './controllers/adminapi/wechat/reply.controller';
import { TemplateController as AdminapiWechatTemplateController } from './controllers/adminapi/wechat/template.controller';
import { ConfigController as AdminapiWxoplatformConfigController } from './controllers/adminapi/wxoplatform/config.controller';
import { OplatformController as AdminapiWxoplatformOplatformController } from './controllers/adminapi/wxoplatform/oplatform.controller';
import { ServerController as AdminapiWxoplatformServerController } from './controllers/adminapi/wxoplatform/server.controller';
import { WeappVersionController as AdminapiWxoplatformWeappVersionController } from './controllers/adminapi/wxoplatform/weapp-version.controller';
import { AddonController as ApiAddonAddonController } from './controllers/api/addon/addon.controller';
import { AgreementController as ApiAgreementAgreementController } from './controllers/api/agreement/agreement.controller';
import { AppController as ApiChannelAppController } from './controllers/api/channel/app.controller';
import { DiyController as ApiDiyDiyController } from './controllers/api/diy/diy.controller';
import { DiyFormController as ApiDiyDiyFormController } from './controllers/api/diy/diy-form.controller';
import { LoginController as ApiLoginLoginController } from './controllers/api/login/login.controller';
import { RegisterController as ApiLoginRegisterController } from './controllers/api/login/register.controller';
import { MemberAccountController as ApiMemberMemberAccountController } from './controllers/api/member/member-account.controller';
import { MemberAddressController as ApiMemberMemberAddressController } from './controllers/api/member/member-address.controller';
import { MemberCashOutController as ApiMemberMemberCashOutController } from './controllers/api/member/member-cash-out.controller';
import { MemberController as ApiMemberMemberController } from './controllers/api/member/member.controller';
import { MemberSignController as ApiMemberMemberSignController } from './controllers/api/member/member-sign.controller';
import { PayController as ApiPayPayController } from './controllers/api/pay/pay.controller';
import { CaptchaController as ApiSysCaptchaController } from './controllers/api/sys/captcha.controller';
import { SysAreaController as ApiSysSysAreaController } from './controllers/api/sys/sys-area.controller';
import { SysConfigController as ApiSysSysConfigController } from './controllers/api/sys/sys-config.controller';
import { SysPosterController as ApiSysSysPosterController } from './controllers/api/sys/sys-poster.controller';
import { SysVerifyController as ApiSysSysVerifyController } from './controllers/api/sys/sys-verify.controller';
import { TaskController as ApiSysTaskController } from './controllers/api/sys/.controller';
import { UploadController as ApiSysUploadController } from './controllers/api/sys/upload.controller';
import { ServeController as ApiWeappServeController } from './controllers/api/weapp/serve.controller';
import { WeappController as ApiWeappWeappController } from './controllers/api/weapp/weapp.controller';
import { ServeController as ApiWechatServeController } from './controllers/api/wechat/serve.controller';
import { WechatController as ApiWechatWechatController } from './controllers/api/wechat/wechat.controller';
import { CoreAddonController as CoreCoreAddonController } from './controllers/core/core-addon.controller';
import { CoreAsyncTaskController as CoreCoreAsyncTaskController } from './controllers/core/core-async.controller';
import { CoreQueueControlController as CoreCoreQueueControlController } from './controllers/core/core-queue-control.controller';
import { HttpServerErrorController as CoreHttpServerErrorController } from './controllers/core/http-server-error.controller';
/**
* ControllerModule - 控制器模块
* 符合NestJS官方规范
* 自动注册110个控制器
*/
@Module({
imports: [
ServiceModule,
],
controllers: [
NiuExceptionHandlerController,
AdminapiIndexController,
AdminapiAddonAddonController,
AdminapiAddonAddonDevelopController,
AdminapiAddonAddonLogController,
AdminapiAddonAppController,
AdminapiAddonBackupController,
AdminapiAddonUpgradeController,
AdminapiAliappConfigController,
AdminapiAuthAuthController,
AdminapiChannelAppController,
AdminapiChannelH5Controller,
AdminapiChannelPcController,
AdminapiDictDictController,
AdminapiDiyConfigController,
AdminapiDiyDiyController,
AdminapiDiyDiyFormController,
AdminapiDiyDiyRouteController,
AdminapiDiyDiyThemeController,
AdminapiGeneratorGenerateController,
AdminapiHomeSiteController,
AdminapiIndexPromotionAdvController,
AdminapiLoginCaptchaController,
AdminapiLoginConfigController,
AdminapiLoginLoginController,
AdminapiMemberMemberAccountController,
AdminapiMemberMemberAddressController,
AdminapiMemberMemberCashOutController,
AdminapiMemberMemberConfigController,
AdminapiMemberMemberController,
AdminapiMemberMemberLabelController,
AdminapiMemberMemberLevelController,
AdminapiMemberMemberSignController,
AdminapiNiucloudCloudController,
AdminapiNiucloudModuleController,
AdminapiNoticeNiuSmsController,
AdminapiNoticeNoticeController,
AdminapiNoticeNoticeLogController,
AdminapiNoticeNoticeSmsLogController,
AdminapiPayPayChannelController,
AdminapiPayPayController,
AdminapiPayPayRefundController,
AdminapiPayPayTransferController,
AdminapiSiteSiteAccountLogController,
AdminapiSiteSiteController,
AdminapiSiteSiteGroupController,
AdminapiSiteUserController,
AdminapiSiteUserLogController,
AdminapiStatStatController,
AdminapiStatStatHourController,
AdminapiSysSysAgreementController,
AdminapiSysSysAreaController,
AdminapiSysSysAttachmentController,
AdminapiSysSysConfigController,
AdminapiSysSysExportController,
AdminapiSysSysMenuController,
AdminapiSysSysNoticeController,
AdminapiSysSysPosterController,
AdminapiSysSysPrinterController,
AdminapiSysSysPrinterTemplateController,
AdminapiSysSysRoleController,
AdminapiSysSysScheduleController,
AdminapiSysSysUeditorController,
AdminapiSysSysUserRoleController,
AdminapiSysSysWebConfigController,
AdminapiSysSystemController,
AdminapiUploadStorageController,
AdminapiUserUserController,
AdminapiVerifyVerifierController,
AdminapiVerifyVerifyController,
AdminapiWeappConfigController,
AdminapiWeappTemplateController,
AdminapiWeappVersionController,
AdminapiWechatConfigController,
AdminapiWechatMediaController,
AdminapiWechatMenuController,
AdminapiWechatReplyController,
AdminapiWechatTemplateController,
AdminapiWxoplatformConfigController,
AdminapiWxoplatformOplatformController,
AdminapiWxoplatformServerController,
AdminapiWxoplatformWeappVersionController,
ApiAddonAddonController,
ApiAgreementAgreementController,
ApiChannelAppController,
ApiDiyDiyController,
ApiDiyDiyFormController,
ApiLoginLoginController,
ApiLoginRegisterController,
ApiMemberMemberAccountController,
ApiMemberMemberAddressController,
ApiMemberMemberCashOutController,
ApiMemberMemberController,
ApiMemberMemberSignController,
ApiPayPayController,
ApiSysCaptchaController,
ApiSysSysAreaController,
ApiSysSysConfigController,
ApiSysSysPosterController,
ApiSysSysVerifyController,
ApiSysTaskController,
ApiSysUploadController,
ApiWeappServeController,
ApiWeappWeappController,
ApiWechatServeController,
ApiWechatWechatController,
CoreCoreAddonController,
CoreCoreAsyncTaskController,
CoreCoreQueueControlController,
CoreHttpServerErrorController,
],
providers: [],
exports: [],
})

View File

@@ -7,6 +7,9 @@
export * from './common/base.dto';
export * from './common/base.entity';
// 主模块导出
export { AppModule } from './app.module';
// 注意具体的controllers、services、entities、dtos、enums等
// 将由Java迁移工具自动生成

View File

@@ -1,19 +1,678 @@
import { Module } from '@nestjs/common';
import { EntityModule } from './entity.module';
import { CachedServiceImplService } from './services/cached-service-impl.service';
import { CachedServiceSupportService } from './services/cached-service-support.service';
import { ThreadPoolManagerService } from './services/thread-pool-manager.service';
import { Example1HandlerProviderImplService } from './services/example1-handler-provider-impl.service';
import { Example2HandlerProviderImplService } from './services/example2-handler-provider-impl.service';
import { QuartzJobManagerService } from './services/quartz-job-manager.service';
import { ControllerRequestAspectService } from './services/controller-request-aspect.service';
import { MethodCallStackAspectService } from './services/method-call-stack-aspect.service';
import { ResourceLoaderContextService } from './services/resource-loader-context.service';
import { MySaTokenListenerService } from './services/my-sa-token.service';
import { UnknownClassService } from './services/unknown-class.service';
import { CoreSpringContextListenerService } from './services/core-spring-context.service';
import { SaTokenAdminInterceptorService } from './services/sa-token-admin-interceptor.service';
import { SaTokenApiInterceptorService } from './services/sa-token-api-interceptor.service';
import { SaTokenInterceptorService } from './services/sa-token-interceptor.service';
import { QuartzConfigService } from './services/quartz-config.service';
import { CustomCellWriteHandlerService } from './services/custom-cell-write-handler.service';
import { RequestUtilsService } from './services/request-utils.service';
import { HttpConnectionPoolManagerDemoService } from './services/http-connection-pool-manager-demo.service';
import { ShowMarketingEnumService } from './services/show-marketing.service';
import { CoreEventListenerService } from './services/core-event.service';
import { CoreExampleEventListenerService } from './services/core-example-event.service';
import { DemoEventListenerService } from './services/demo-event.service';
import { ShopExampleEventListenerService } from './services/shop-example-event.service';
import { MemberAccountListenerService } from './services/member-account.service';
import { MemberCashOutTransferSuccessListenerService } from './services/member-cash-out-transfer-success.service';
import { MemberRegisterListenerService } from './services/member-register.service';
import { SmsSendNoticeEventListenerService } from './services/sms-send-notice-event.service';
import { WeappSendNoticeEventListenerService } from './services/weapp-send-notice-event.service';
import { WechatSendNoticeEventListenerService } from './services/wechat-send-notice-event.service';
import { PaySuccessListenerService } from './services/pay-success.service';
import { RefundSuccessListenerService } from './services/refund-success.service';
import { TransferSuccessListenerService } from './services/transfer-success.service';
import { GetPosterDataListenerService } from './services/get-poster-data.service';
import { SiteAddAfterListenerService } from './services/site-add-after.service';
import { MemberExportDataListenerService } from './services/member-export-data.service';
import { PosterDrawListenerService } from './services/poster-draw.service';
import { ShowCustomerListenerService } from './services/show-customer.service';
import { WeappQrcodeListenerService } from './services/weapp-qrcode.service';
import { WechatQrcodeListenerService } from './services/wechat-qrcode.service';
import { TestListenerService } from './services/test.service';
import { AddonDevelopBuildServiceImplService } from './services/admin/addon/impl/addon-develop-build-service-impl.service';
import { AddonDevelopServiceImplService } from './services/admin/addon/impl/addon-develop-service-impl.service';
import { AddonLogServiceImplService } from './services/admin/addon/impl/addon-log-service-impl.service';
import { AddonServiceImplService } from './services/admin/addon/impl/addon-service-impl.service';
import { AliappConfigServiceImplService } from './services/admin/aliapp/impl/aliapp-config-service-impl.service';
import { AuthServiceImplService as AdminAuthImplAuthServiceImplService } from './services/admin/auth/impl/auth-service-impl.service';
import { ConfigServiceImplService } from './services/admin/auth/impl/config-service-impl.service';
import { LoginServiceImplService as AdminAuthImplLoginServiceImplService } from './services/admin/auth/impl/login-service-impl.service';
import { CaptchaCacheServiceRedisImplService } from './services/admin/captcha/cache/captcha-cache-service-redis-impl.service';
import { CaptchaServiceImplService } from './services/admin/captcha/impl/captcha-service-impl.service';
import { AdminAppServiceImplService } from './services/admin/channel/impl/admin-app-service-impl.service';
import { DictServiceImplService } from './services/admin/dict/impl/dict-service-impl.service';
import { DiyConfigServiceImplService } from './services/admin/diy/impl/diy-config-service-impl.service';
import { DiyRouteServiceImplService } from './services/admin/diy/impl/diy-route-service-impl.service';
import { DiyServiceImplService as AdminDiyImplDiyServiceImplService } from './services/admin/diy/impl/diy-service-impl.service';
import { DiyThemeServiceImplService } from './services/admin/diy/impl/diy-theme-service-impl.service';
import { DiyFormConfigServiceImplService } from './services/admin/diy_form/impl/diy-form-config-service-impl.service';
import { DiyFormRecordsServiceImplService } from './services/admin/diy_form/impl/diy-form-records-service-impl.service';
import { DiyFormServiceImplService as AdminDiy_formImplDiyFormServiceImplService } from './services/admin/diy_form/impl/diy-form-service-impl.service';
import { GenerateColumnServiceImplService } from './services/admin/generator/impl/generate-column-service-impl.service';
import { GenerateServiceImplService } from './services/admin/generator/impl/generate-service-impl.service';
import { AuthSiteServiceImplService } from './services/admin/home/impl/auth-site-service-impl.service';
import { InstallSystemServiceImplService } from './services/admin/install/impl/install-system-service-impl.service';
import { MemberAccountServiceImplService as AdminMemberImplMemberAccountServiceImplService } from './services/admin/member/impl/member-account-service-impl.service';
import { MemberAddressServiceImplService as AdminMemberImplMemberAddressServiceImplService } from './services/admin/member/impl/member-address-service-impl.service';
import { MemberCashOutServiceImplService as AdminMemberImplMemberCashOutServiceImplService } from './services/admin/member/impl/member-cash-out-service-impl.service';
import { MemberConfigServiceImplService } from './services/admin/member/impl/member-config-service-impl.service';
import { MemberLabelServiceImplService } from './services/admin/member/impl/member-label-service-impl.service';
import { MemberLevelServiceImplService as AdminMemberImplMemberLevelServiceImplService } from './services/admin/member/impl/member-level-service-impl.service';
import { MemberServiceImplService as AdminMemberImplMemberServiceImplService } from './services/admin/member/impl/member-service-impl.service';
import { MemberSignServiceImplService as AdminMemberImplMemberSignServiceImplService } from './services/admin/member/impl/member-sign-service-impl.service';
import { CloudBuildServiceImplService } from './services/admin/niucloud/impl/cloud-build-service-impl.service';
import { NiuCloudServiceImplService } from './services/admin/niucloud/impl/niu-cloud-service-impl.service';
import { NoticeLogServiceImplService } from './services/admin/notice/impl/notice-log-service-impl.service';
import { NoticeServiceImplService } from './services/admin/notice/impl/notice-service-impl.service';
import { NuiSmsServiceImplService } from './services/admin/notice/impl/nui-sms-service-impl.service';
import { SmsServiceService } from './services/admin/notice/impl/sms.service';
import { PayChannelServiceImplService } from './services/admin/pay/impl/pay-channel-service-impl.service';
import { PayRefundServiceImplService } from './services/admin/pay/impl/pay-refund-service-impl.service';
import { PayServiceImplService as AdminPayImplPayServiceImplService } from './services/admin/pay/impl/pay-service-impl.service';
import { PayTransferServiceImplService } from './services/admin/pay/impl/pay-transfer-service-impl.service';
import { SiteAccountLogServiceImplService } from './services/admin/site/impl/site-account-log-service-impl.service';
import { SiteGroupServiceImplService } from './services/admin/site/impl/site-group-service-impl.service';
import { SiteServiceImplService } from './services/admin/site/impl/site-service-impl.service';
import { SiteUserServiceImplService } from './services/admin/site/impl/site-user-service-impl.service';
import { StatHourServiceImplService } from './services/admin/stat/impl/stat-hour-service-impl.service';
import { StatServiceImplService } from './services/admin/stat/impl/stat-service-impl.service';
import { SysAgreementServiceImplService } from './services/admin/sys/impl/sys-agreement-service-impl.service';
import { SysAreaServiceImplService as AdminSysImplSysAreaServiceImplService } from './services/admin/sys/impl/sys-area-service-impl.service';
import { SysAttachmentServiceImplService } from './services/admin/sys/impl/sys-attachment-service-impl.service';
import { SysBackupRecordsServiceImplService } from './services/admin/sys/impl/sys-backup-records-service-impl.service';
import { SysConfigServiceImplService as AdminSysImplSysConfigServiceImplService } from './services/admin/sys/impl/sys-config-service-impl.service';
import { SysExportServiceImplService } from './services/admin/sys/impl/sys-export-service-impl.service';
import { SysMenuServiceImplService } from './services/admin/sys/impl/sys-menu-service-impl.service';
import { SysNoticeLogServiceImplService } from './services/admin/sys/impl/sys-notice-log-service-impl.service';
import { SysNoticeServiceImplService } from './services/admin/sys/impl/sys-notice-service-impl.service';
import { SysNoticeSmsLogServiceImplService } from './services/admin/sys/impl/sys-notice-sms-log-service-impl.service';
import { SysPosterServiceImplService } from './services/admin/sys/impl/sys-poster-service-impl.service';
import { SysPrinterServiceImplService } from './services/admin/sys/impl/sys-printer-service-impl.service';
import { SysPrinterTemplateServiceImplService } from './services/admin/sys/impl/sys-printer-template-service-impl.service';
import { SysRoleServiceImplService } from './services/admin/sys/impl/sys-role-service-impl.service';
import { SysScheduleServiceImplService } from './services/admin/sys/impl/sys-schedule-service-impl.service';
import { SysUpgradeRecordsServiceImplService } from './services/admin/sys/impl/sys-upgrade-records-service-impl.service';
import { SysUserLogServiceImplService } from './services/admin/sys/impl/sys-user-log-service-impl.service';
import { SysUserRoleServiceImplService } from './services/admin/sys/impl/sys-user-role-service-impl.service';
import { SysUserServiceImplService } from './services/admin/sys/impl/sys-user-service-impl.service';
import { SystemServiceImplService } from './services/admin/sys/impl/system-service-impl.service';
import { SysServiceVoService } from './services/admin/sys/vo/sys-service-vo.service';
import { UpgradeServiceImplService } from './services/admin/upgrade/impl/upgrade-service-impl.service';
import { StorageConfigServiceImplService } from './services/admin/upload/impl/storage-config-service-impl.service';
import { VerifierServiceImplService } from './services/admin/verify/impl/verifier-service-impl.service';
import { VerifyServiceImplService } from './services/admin/verify/impl/verify-service-impl.service';
import { WeappConfigServiceImplService } from './services/admin/weapp/impl/weapp-config-service-impl.service';
import { WeappTemplateServiceImplService } from './services/admin/weapp/impl/weapp-template-service-impl.service';
import { WeappVersionServiceImplService as AdminWeappImplWeappVersionServiceImplService } from './services/admin/weapp/impl/weapp-version-service-impl.service';
import { WechatConfigServiceImplService } from './services/admin/wechat/impl/wechat-config-service-impl.service';
import { WechatMediaServiceImplService } from './services/admin/wechat/impl/wechat-media-service-impl.service';
import { WechatMenuServiceImplService } from './services/admin/wechat/impl/wechat-menu-service-impl.service';
import { WechatReplyServiceImplService } from './services/admin/wechat/impl/wechat-reply-service-impl.service';
import { WechatTemplateServiceImplService } from './services/admin/wechat/impl/wechat-template-service-impl.service';
import { OplatformConfigServiceImplService } from './services/admin/wxoplatform/impl/oplatform-config-service-impl.service';
import { OplatformServerServiceImplService } from './services/admin/wxoplatform/impl/oplatform-server-service-impl.service';
import { OplatformServiceImplService } from './services/admin/wxoplatform/impl/oplatform-service-impl.service';
import { WeappVersionServiceImplService as AdminWxoplatformImplWeappVersionServiceImplService } from './services/admin/wxoplatform/impl/weapp-version-service-impl.service';
import { AgreementServiceImplService } from './services/api/agreement/impl/agreement-service-impl.service';
import { AppServiceImplService } from './services/api/channel/impl/app-service-impl.service';
import { DiyFormServiceImplService as ApiDiyImplDiyFormServiceImplService } from './services/api/diy/impl/diy-form-service-impl.service';
import { DiyServiceImplService as ApiDiyImplDiyServiceImplService } from './services/api/diy/impl/diy-service-impl.service';
import { AuthServiceImplService as ApiLoginImplAuthServiceImplService } from './services/api/login/impl/auth-service-impl.service';
import { LoginServiceImplService as ApiLoginImplLoginServiceImplService } from './services/api/login/impl/login-service-impl.service';
import { RegisterServiceImplService } from './services/api/login/impl/register-service-impl.service';
import { MemberAccountServiceImplService as ApiMemberImplMemberAccountServiceImplService } from './services/api/member/impl/member-account-service-impl.service';
import { MemberAddressServiceImplService as ApiMemberImplMemberAddressServiceImplService } from './services/api/member/impl/member-address-service-impl.service';
import { MemberCashOutServiceImplService as ApiMemberImplMemberCashOutServiceImplService } from './services/api/member/impl/member-cash-out-service-impl.service';
import { MemberLevelServiceImplService as ApiMemberImplMemberLevelServiceImplService } from './services/api/member/impl/member-level-service-impl.service';
import { MemberServiceImplService as ApiMemberImplMemberServiceImplService } from './services/api/member/impl/member-service-impl.service';
import { MemberSignServiceImplService as ApiMemberImplMemberSignServiceImplService } from './services/api/member/impl/member-sign-service-impl.service';
import { PayServiceImplService as ApiPayImplPayServiceImplService } from './services/api/pay/impl/pay-service-impl.service';
import { Base64ServiceImplService } from './services/api/sys/impl/base64-service-impl.service';
import { SysAreaServiceImplService as ApiSysImplSysAreaServiceImplService } from './services/api/sys/impl/sys-area-service-impl.service';
import { SysConfigServiceImplService as ApiSysImplSysConfigServiceImplService } from './services/api/sys/impl/sys-config-service-impl.service';
import { SysVerifyServiceImplService } from './services/api/sys/impl/sys-verify-service-impl.service';
import { TaskServiceImplService } from './services/api/sys/impl/task-service-impl.service';
import { UploadServiceImplService } from './services/api/sys/impl/upload-service-impl.service';
import { ServeServiceImplService as ApiWeappImplServeServiceImplService } from './services/api/weapp/impl/serve-service-impl.service';
import { WeappServiceImplService } from './services/api/weapp/impl/weapp-service-impl.service';
import { MessageHandleImplService } from './services/api/wechat/impl/message-handle-impl.service';
import { ServeServiceImplService as ApiWechatImplServeServiceImplService } from './services/api/wechat/impl/serve-service-impl.service';
import { WechatServiceImplService } from './services/api/wechat/impl/wechat-service-impl.service';
import { AddonInstallToolsService } from './services/core/addon/addon-install-tools.service';
import { CoreAddonBaseServiceService } from './services/core/addon/core-addon-base.service';
import { CoreAddonInstallServiceImplService } from './services/core/addon/impl/core-addon-install-service-impl.service';
import { CoreAddonServiceImplService } from './services/core/addon/impl/core-addon-service-impl.service';
import { CoreAliappConfigServiceImplService } from './services/core/aliapp/impl/core-aliapp-config-service-impl.service';
import { CoreAppServiceImplService as CoreAppImplCoreAppServiceImplService } from './services/core/app/impl/core-app-service-impl.service';
import { CoreAsyncTaskServiceImplService } from './services/core/app/impl/core-async-task-service-impl.service';
import { CoreQueueServiceImplService } from './services/core/app/impl/core-queue-service-impl.service';
import { CoreCaptchaImgServiceImplService } from './services/core/captcha/impl/core-captcha-img-service-impl.service';
import { DefaultCaptchaServiceImplService } from './services/core/captcha/impl/default-captcha-service-impl.service';
import { CoreAppCloudServiceImplService } from './services/core/channel/impl/core-app-cloud-service-impl.service';
import { CoreAppServiceImplService as CoreChannelImplCoreAppServiceImplService } from './services/core/channel/impl/core-app-service-impl.service';
import { CoreH5ServiceImplService } from './services/core/channel/impl/core-h5-service-impl.service';
import { CorePcServiceImplService } from './services/core/channel/impl/core-pc-service-impl.service';
import { CoreDiyConfigServiceService } from './services/core/diy/impl/core-diy-config.service';
import { CoreDiyServiceImplService } from './services/core/diy/impl/core-diy-service-impl.service';
import { DiyFormDriverService } from './services/core/diy_form/driver/diy-form-driver.service';
import { CoreDiyFormConfigServiceImplService } from './services/core/diy_form/impl/core-diy-form-config-service-impl.service';
import { CoreDiyFormRecordsServiceImplService } from './services/core/diy_form/impl/core-diy-form-records-service-impl.service';
import { CoreGenerateServiceService } from './services/core/generator/core-generate.service';
import { CorePromotionAdvServiceService } from './services/core/index/impl/core-promotion-adv.service';
import { BenefitsDriverService } from './services/core/member/driver/benefits-driver.service';
import { GiftBalanceDriverService } from './services/core/member/driver/gift-balance-driver.service';
import { GiftPointDriverService } from './services/core/member/driver/gift-point-driver.service';
import { GrowthRuleRegisterDriverService } from './services/core/member/driver/growth-rule-register-driver.service';
import { PointRuleRegisterDriverService } from './services/core/member/driver/point-rule-register-driver.service';
import { CoreMemberAccountServiceImplService } from './services/core/member/impl/core-member-account-service-impl.service';
import { CoreMemberCashOutServiceImplService } from './services/core/member/impl/core-member-cash-out-service-impl.service';
import { CoreMemberConfigServiceImplService } from './services/core/member/impl/core-member-config-service-impl.service';
import { CoreMemberLevelServiceImplService } from './services/core/member/impl/core-member-level-service-impl.service';
import { CoreMemberServiceImplService } from './services/core/member/impl/core-member-service-impl.service';
import { CoreNoticeLogServiceService } from './services/core/notice/impl/core-notice-log.service';
import { CoreNoticeServiceImplService } from './services/core/notice/impl/core-notice-service-impl.service';
import { CoreNoticeSmsLogServiceImplService } from './services/core/notice/impl/core-notice-sms-log-service-impl.service';
import { AlipayService } from './services/core/pay/driver/alipay.service';
import { BalancepayService } from './services/core/pay/driver/balancepay.service';
import { FriendPayService } from './services/core/pay/driver/friend-pay.service';
import { WechatpayService } from './services/core/pay/driver/wechatpay.service';
import { CorePayChannelServiceImplService } from './services/core/pay/impl/core-pay-channel-service-impl.service';
import { CorePayEventServiceImplService } from './services/core/pay/impl/core-pay-event-service-impl.service';
import { CorePayServiceImplService } from './services/core/pay/impl/core-pay-service-impl.service';
import { CoreRefundServiceImplService } from './services/core/pay/impl/core-refund-service-impl.service';
import { CoreTransferSceneServiceImplService } from './services/core/pay/impl/core-transfer-scene-service-impl.service';
import { CoreTransferServiceImplService } from './services/core/pay/impl/core-transfer-service-impl.service';
import { CorePosterServiceImplService } from './services/core/poster/impl/core-poster-service-impl.service';
import { CoreScheduleServiceImplService } from './services/core/schedule/impl/core-schedule-service-impl.service';
import { CoreSiteServiceFactoryService } from './services/core/site/factory/core-site-service-factory.service';
import { CoreSiteAccountServiceImplService } from './services/core/site/impl/core-site-account-service-impl.service';
import { CoreSiteServiceImplService } from './services/core/site/impl/core-site-service-impl.service';
import { CoreSmsServiceImplService } from './services/core/sms/impl/core-sms-service-impl.service';
import { CoreAgreementServiceImplService } from './services/core/sys/impl/core-agreement-service-impl.service';
import { CoreConfigServiceImplService } from './services/core/sys/impl/core-config-service-impl.service';
import { CoreExportServiceImplService } from './services/core/sys/impl/core-export-service-impl.service';
import { CoreMenuServiceImplService } from './services/core/sys/impl/core-menu-service-impl.service';
import { CorePrinterServiceImplService } from './services/core/sys/impl/core-printer-service-impl.service';
import { CoreScanServiceImplService } from './services/core/sys/impl/core-scan-service-impl.service';
import { CoreSysConfigServiceImplService } from './services/core/sys/impl/core-sys-config-service-impl.service';
import { CoreUploadServiceImplService } from './services/core/sys/impl/core-upload-service-impl.service';
import { CoreBase64ServiceImplService } from './services/core/upload/impl/core-base64-service-impl.service';
import { CoreFetchServiceImplService } from './services/core/upload/impl/core-fetch-service-impl.service';
import { CoreStorageServiceImplService } from './services/core/upload/impl/core-storage-service-impl.service';
import { CoreUserServiceImplService } from './services/core/user/impl/core-user-service-impl.service';
import { CoreWeappCloudServiceImplService } from './services/core/weapp/impl/core-weapp-cloud-service-impl.service';
import { CoreWeappConfigServiceImplService } from './services/core/weapp/impl/core-weapp-config-service-impl.service';
import { CoreWeappDeliveryServiceImplService } from './services/core/weapp/impl/core-weapp-delivery-service-impl.service';
import { CoreWeappServiceImplService } from './services/core/weapp/impl/core-weapp-service-impl.service';
import { CoreWechatConfigServiceImplService } from './services/core/wechat/impl/core-wechat-config-service-impl.service';
import { CoreWechatReplyServiceImplService } from './services/core/wechat/impl/core-wechat-reply-service-impl.service';
import { CoreOplatformServiceImplService } from './services/core/wxoplatform/impl/core-oplatform-service-impl.service';
import { CoreOplatformStaticConfigServiceImplService } from './services/core/wxoplatform/impl/core-oplatform-static-config-service-impl.service';
/**
* ServiceModule - 服务模块
* 符合NestJS官方规范
* 自动注册220个服务
*/
@Module({
imports: [
EntityModule,
],
providers: [
// 无提供者
CachedServiceImplService,
CachedServiceSupportService,
ThreadPoolManagerService,
Example1HandlerProviderImplService,
Example2HandlerProviderImplService,
QuartzJobManagerService,
ControllerRequestAspectService,
MethodCallStackAspectService,
ResourceLoaderContextService,
MySaTokenListenerService,
UnknownClassService,
CoreSpringContextListenerService,
SaTokenAdminInterceptorService,
SaTokenApiInterceptorService,
SaTokenInterceptorService,
QuartzConfigService,
CustomCellWriteHandlerService,
RequestUtilsService,
HttpConnectionPoolManagerDemoService,
ShowMarketingEnumService,
CoreEventListenerService,
CoreExampleEventListenerService,
DemoEventListenerService,
ShopExampleEventListenerService,
MemberAccountListenerService,
MemberCashOutTransferSuccessListenerService,
MemberRegisterListenerService,
SmsSendNoticeEventListenerService,
WeappSendNoticeEventListenerService,
WechatSendNoticeEventListenerService,
PaySuccessListenerService,
RefundSuccessListenerService,
TransferSuccessListenerService,
GetPosterDataListenerService,
SiteAddAfterListenerService,
MemberExportDataListenerService,
PosterDrawListenerService,
ShowCustomerListenerService,
WeappQrcodeListenerService,
WechatQrcodeListenerService,
TestListenerService,
AddonDevelopBuildServiceImplService,
AddonDevelopServiceImplService,
AddonLogServiceImplService,
AddonServiceImplService,
AliappConfigServiceImplService,
AdminAuthImplAuthServiceImplService,
ConfigServiceImplService,
AdminAuthImplLoginServiceImplService,
CaptchaCacheServiceRedisImplService,
CaptchaServiceImplService,
AdminAppServiceImplService,
DictServiceImplService,
DiyConfigServiceImplService,
DiyRouteServiceImplService,
AdminDiyImplDiyServiceImplService,
DiyThemeServiceImplService,
DiyFormConfigServiceImplService,
DiyFormRecordsServiceImplService,
AdminDiy_formImplDiyFormServiceImplService,
GenerateColumnServiceImplService,
GenerateServiceImplService,
AuthSiteServiceImplService,
InstallSystemServiceImplService,
AdminMemberImplMemberAccountServiceImplService,
AdminMemberImplMemberAddressServiceImplService,
AdminMemberImplMemberCashOutServiceImplService,
MemberConfigServiceImplService,
MemberLabelServiceImplService,
AdminMemberImplMemberLevelServiceImplService,
AdminMemberImplMemberServiceImplService,
AdminMemberImplMemberSignServiceImplService,
CloudBuildServiceImplService,
NiuCloudServiceImplService,
NoticeLogServiceImplService,
NoticeServiceImplService,
NuiSmsServiceImplService,
SmsServiceService,
PayChannelServiceImplService,
PayRefundServiceImplService,
AdminPayImplPayServiceImplService,
PayTransferServiceImplService,
SiteAccountLogServiceImplService,
SiteGroupServiceImplService,
SiteServiceImplService,
SiteUserServiceImplService,
StatHourServiceImplService,
StatServiceImplService,
SysAgreementServiceImplService,
AdminSysImplSysAreaServiceImplService,
SysAttachmentServiceImplService,
SysBackupRecordsServiceImplService,
AdminSysImplSysConfigServiceImplService,
SysExportServiceImplService,
SysMenuServiceImplService,
SysNoticeLogServiceImplService,
SysNoticeServiceImplService,
SysNoticeSmsLogServiceImplService,
SysPosterServiceImplService,
SysPrinterServiceImplService,
SysPrinterTemplateServiceImplService,
SysRoleServiceImplService,
SysScheduleServiceImplService,
SysUpgradeRecordsServiceImplService,
SysUserLogServiceImplService,
SysUserRoleServiceImplService,
SysUserServiceImplService,
SystemServiceImplService,
SysServiceVoService,
UpgradeServiceImplService,
StorageConfigServiceImplService,
VerifierServiceImplService,
VerifyServiceImplService,
WeappConfigServiceImplService,
WeappTemplateServiceImplService,
AdminWeappImplWeappVersionServiceImplService,
WechatConfigServiceImplService,
WechatMediaServiceImplService,
WechatMenuServiceImplService,
WechatReplyServiceImplService,
WechatTemplateServiceImplService,
OplatformConfigServiceImplService,
OplatformServerServiceImplService,
OplatformServiceImplService,
AdminWxoplatformImplWeappVersionServiceImplService,
AgreementServiceImplService,
AppServiceImplService,
ApiDiyImplDiyFormServiceImplService,
ApiDiyImplDiyServiceImplService,
ApiLoginImplAuthServiceImplService,
ApiLoginImplLoginServiceImplService,
RegisterServiceImplService,
ApiMemberImplMemberAccountServiceImplService,
ApiMemberImplMemberAddressServiceImplService,
ApiMemberImplMemberCashOutServiceImplService,
ApiMemberImplMemberLevelServiceImplService,
ApiMemberImplMemberServiceImplService,
ApiMemberImplMemberSignServiceImplService,
ApiPayImplPayServiceImplService,
Base64ServiceImplService,
ApiSysImplSysAreaServiceImplService,
ApiSysImplSysConfigServiceImplService,
SysVerifyServiceImplService,
TaskServiceImplService,
UploadServiceImplService,
ApiWeappImplServeServiceImplService,
WeappServiceImplService,
MessageHandleImplService,
ApiWechatImplServeServiceImplService,
WechatServiceImplService,
AddonInstallToolsService,
CoreAddonBaseServiceService,
CoreAddonInstallServiceImplService,
CoreAddonServiceImplService,
CoreAliappConfigServiceImplService,
CoreAppImplCoreAppServiceImplService,
CoreAsyncTaskServiceImplService,
CoreQueueServiceImplService,
CoreCaptchaImgServiceImplService,
DefaultCaptchaServiceImplService,
CoreAppCloudServiceImplService,
CoreChannelImplCoreAppServiceImplService,
CoreH5ServiceImplService,
CorePcServiceImplService,
CoreDiyConfigServiceService,
CoreDiyServiceImplService,
DiyFormDriverService,
CoreDiyFormConfigServiceImplService,
CoreDiyFormRecordsServiceImplService,
CoreGenerateServiceService,
CorePromotionAdvServiceService,
BenefitsDriverService,
GiftBalanceDriverService,
GiftPointDriverService,
GrowthRuleRegisterDriverService,
PointRuleRegisterDriverService,
CoreMemberAccountServiceImplService,
CoreMemberCashOutServiceImplService,
CoreMemberConfigServiceImplService,
CoreMemberLevelServiceImplService,
CoreMemberServiceImplService,
CoreNoticeLogServiceService,
CoreNoticeServiceImplService,
CoreNoticeSmsLogServiceImplService,
AlipayService,
BalancepayService,
FriendPayService,
WechatpayService,
CorePayChannelServiceImplService,
CorePayEventServiceImplService,
CorePayServiceImplService,
CoreRefundServiceImplService,
CoreTransferSceneServiceImplService,
CoreTransferServiceImplService,
CorePosterServiceImplService,
CoreScheduleServiceImplService,
CoreSiteServiceFactoryService,
CoreSiteAccountServiceImplService,
CoreSiteServiceImplService,
CoreSmsServiceImplService,
CoreAgreementServiceImplService,
CoreConfigServiceImplService,
CoreExportServiceImplService,
CoreMenuServiceImplService,
CorePrinterServiceImplService,
CoreScanServiceImplService,
CoreSysConfigServiceImplService,
CoreUploadServiceImplService,
CoreBase64ServiceImplService,
CoreFetchServiceImplService,
CoreStorageServiceImplService,
CoreUserServiceImplService,
CoreWeappCloudServiceImplService,
CoreWeappConfigServiceImplService,
CoreWeappDeliveryServiceImplService,
CoreWeappServiceImplService,
CoreWechatConfigServiceImplService,
CoreWechatReplyServiceImplService,
CoreOplatformServiceImplService,
CoreOplatformStaticConfigServiceImplService,
],
exports: [
// 无导出
CachedServiceImplService,
CachedServiceSupportService,
ThreadPoolManagerService,
Example1HandlerProviderImplService,
Example2HandlerProviderImplService,
QuartzJobManagerService,
ControllerRequestAspectService,
MethodCallStackAspectService,
ResourceLoaderContextService,
MySaTokenListenerService,
UnknownClassService,
CoreSpringContextListenerService,
SaTokenAdminInterceptorService,
SaTokenApiInterceptorService,
SaTokenInterceptorService,
QuartzConfigService,
CustomCellWriteHandlerService,
RequestUtilsService,
HttpConnectionPoolManagerDemoService,
ShowMarketingEnumService,
CoreEventListenerService,
CoreExampleEventListenerService,
DemoEventListenerService,
ShopExampleEventListenerService,
MemberAccountListenerService,
MemberCashOutTransferSuccessListenerService,
MemberRegisterListenerService,
SmsSendNoticeEventListenerService,
WeappSendNoticeEventListenerService,
WechatSendNoticeEventListenerService,
PaySuccessListenerService,
RefundSuccessListenerService,
TransferSuccessListenerService,
GetPosterDataListenerService,
SiteAddAfterListenerService,
MemberExportDataListenerService,
PosterDrawListenerService,
ShowCustomerListenerService,
WeappQrcodeListenerService,
WechatQrcodeListenerService,
TestListenerService,
AddonDevelopBuildServiceImplService,
AddonDevelopServiceImplService,
AddonLogServiceImplService,
AddonServiceImplService,
AliappConfigServiceImplService,
AdminAuthImplAuthServiceImplService,
ConfigServiceImplService,
AdminAuthImplLoginServiceImplService,
CaptchaCacheServiceRedisImplService,
CaptchaServiceImplService,
AdminAppServiceImplService,
DictServiceImplService,
DiyConfigServiceImplService,
DiyRouteServiceImplService,
AdminDiyImplDiyServiceImplService,
DiyThemeServiceImplService,
DiyFormConfigServiceImplService,
DiyFormRecordsServiceImplService,
AdminDiy_formImplDiyFormServiceImplService,
GenerateColumnServiceImplService,
GenerateServiceImplService,
AuthSiteServiceImplService,
InstallSystemServiceImplService,
AdminMemberImplMemberAccountServiceImplService,
AdminMemberImplMemberAddressServiceImplService,
AdminMemberImplMemberCashOutServiceImplService,
MemberConfigServiceImplService,
MemberLabelServiceImplService,
AdminMemberImplMemberLevelServiceImplService,
AdminMemberImplMemberServiceImplService,
AdminMemberImplMemberSignServiceImplService,
CloudBuildServiceImplService,
NiuCloudServiceImplService,
NoticeLogServiceImplService,
NoticeServiceImplService,
NuiSmsServiceImplService,
SmsServiceService,
PayChannelServiceImplService,
PayRefundServiceImplService,
AdminPayImplPayServiceImplService,
PayTransferServiceImplService,
SiteAccountLogServiceImplService,
SiteGroupServiceImplService,
SiteServiceImplService,
SiteUserServiceImplService,
StatHourServiceImplService,
StatServiceImplService,
SysAgreementServiceImplService,
AdminSysImplSysAreaServiceImplService,
SysAttachmentServiceImplService,
SysBackupRecordsServiceImplService,
AdminSysImplSysConfigServiceImplService,
SysExportServiceImplService,
SysMenuServiceImplService,
SysNoticeLogServiceImplService,
SysNoticeServiceImplService,
SysNoticeSmsLogServiceImplService,
SysPosterServiceImplService,
SysPrinterServiceImplService,
SysPrinterTemplateServiceImplService,
SysRoleServiceImplService,
SysScheduleServiceImplService,
SysUpgradeRecordsServiceImplService,
SysUserLogServiceImplService,
SysUserRoleServiceImplService,
SysUserServiceImplService,
SystemServiceImplService,
SysServiceVoService,
UpgradeServiceImplService,
StorageConfigServiceImplService,
VerifierServiceImplService,
VerifyServiceImplService,
WeappConfigServiceImplService,
WeappTemplateServiceImplService,
AdminWeappImplWeappVersionServiceImplService,
WechatConfigServiceImplService,
WechatMediaServiceImplService,
WechatMenuServiceImplService,
WechatReplyServiceImplService,
WechatTemplateServiceImplService,
OplatformConfigServiceImplService,
OplatformServerServiceImplService,
OplatformServiceImplService,
AdminWxoplatformImplWeappVersionServiceImplService,
AgreementServiceImplService,
AppServiceImplService,
ApiDiyImplDiyFormServiceImplService,
ApiDiyImplDiyServiceImplService,
ApiLoginImplAuthServiceImplService,
ApiLoginImplLoginServiceImplService,
RegisterServiceImplService,
ApiMemberImplMemberAccountServiceImplService,
ApiMemberImplMemberAddressServiceImplService,
ApiMemberImplMemberCashOutServiceImplService,
ApiMemberImplMemberLevelServiceImplService,
ApiMemberImplMemberServiceImplService,
ApiMemberImplMemberSignServiceImplService,
ApiPayImplPayServiceImplService,
Base64ServiceImplService,
ApiSysImplSysAreaServiceImplService,
ApiSysImplSysConfigServiceImplService,
SysVerifyServiceImplService,
TaskServiceImplService,
UploadServiceImplService,
ApiWeappImplServeServiceImplService,
WeappServiceImplService,
MessageHandleImplService,
ApiWechatImplServeServiceImplService,
WechatServiceImplService,
AddonInstallToolsService,
CoreAddonBaseServiceService,
CoreAddonInstallServiceImplService,
CoreAddonServiceImplService,
CoreAliappConfigServiceImplService,
CoreAppImplCoreAppServiceImplService,
CoreAsyncTaskServiceImplService,
CoreQueueServiceImplService,
CoreCaptchaImgServiceImplService,
DefaultCaptchaServiceImplService,
CoreAppCloudServiceImplService,
CoreChannelImplCoreAppServiceImplService,
CoreH5ServiceImplService,
CorePcServiceImplService,
CoreDiyConfigServiceService,
CoreDiyServiceImplService,
DiyFormDriverService,
CoreDiyFormConfigServiceImplService,
CoreDiyFormRecordsServiceImplService,
CoreGenerateServiceService,
CorePromotionAdvServiceService,
BenefitsDriverService,
GiftBalanceDriverService,
GiftPointDriverService,
GrowthRuleRegisterDriverService,
PointRuleRegisterDriverService,
CoreMemberAccountServiceImplService,
CoreMemberCashOutServiceImplService,
CoreMemberConfigServiceImplService,
CoreMemberLevelServiceImplService,
CoreMemberServiceImplService,
CoreNoticeLogServiceService,
CoreNoticeServiceImplService,
CoreNoticeSmsLogServiceImplService,
AlipayService,
BalancepayService,
FriendPayService,
WechatpayService,
CorePayChannelServiceImplService,
CorePayEventServiceImplService,
CorePayServiceImplService,
CoreRefundServiceImplService,
CoreTransferSceneServiceImplService,
CoreTransferServiceImplService,
CorePosterServiceImplService,
CoreScheduleServiceImplService,
CoreSiteServiceFactoryService,
CoreSiteAccountServiceImplService,
CoreSiteServiceImplService,
CoreSmsServiceImplService,
CoreAgreementServiceImplService,
CoreConfigServiceImplService,
CoreExportServiceImplService,
CoreMenuServiceImplService,
CorePrinterServiceImplService,
CoreScanServiceImplService,
CoreSysConfigServiceImplService,
CoreUploadServiceImplService,
CoreBase64ServiceImplService,
CoreFetchServiceImplService,
CoreStorageServiceImplService,
CoreUserServiceImplService,
CoreWeappCloudServiceImplService,
CoreWeappConfigServiceImplService,
CoreWeappDeliveryServiceImplService,
CoreWeappServiceImplService,
CoreWechatConfigServiceImplService,
CoreWechatReplyServiceImplService,
CoreOplatformServiceImplService,
CoreOplatformStaticConfigServiceImplService,
],
})
export class ServiceModule {}

View File

@@ -29,6 +29,7 @@
"@nestjs/core": "^11.0.1",
"@nestjs/event-emitter": "^3.0.1",
"@nestjs/platform-express": "^11.0.1",
"@nestjs/schedule": "^6.0.1",
"@nestjs/swagger": "^11.2.1",
"@nestjs/terminus": "^11.0.0",
"@nestjs/typeorm": "^11.0.0",

View File

@@ -1,17 +0,0 @@
node_modules
dist
npm-debug.log
.env
.env.local
.env.*.local
.git
.gitignore
.vscode
.idea
*.md
!README.md
test
coverage
.cache
admin

View File

@@ -1,56 +0,0 @@
# compiled output
/dist
/node_modules
/build
# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# OS
.DS_Store
# Tests
/coverage
/.nyc_output
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# temp directory
.temp
.tmp
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

View File

@@ -1,4 +0,0 @@
{
"singleQuote": true,
"trailingComma": "all"
}

View File

@@ -1,140 +0,0 @@
# WWJCloud-Nest 🚀
基于NestJS v11的企业级全栈框架对标Java Spring Boot和PHP ThinkPHP。
## 🏗️ 架构设计
```
WWJCloud NestJS企业级架构
├── Config层 ✅ 框架配置中心 (NuCloud Config)
├── Common层 ✅ 基础设施层 (缓存/日志/监控/异常)
├── Vendor层 ✅ 第三方服务集成 (支付/短信/上传/通知)
├── Core层 🔄 通用业务逻辑 (会员/装修/字典)
└── App层 🔄 具体业务实现 (前台/管理端)
```
## ✨ 核心特性
- 🎯 **企业级框架**:完整的企业应用开发基础设施
- 🔧 **配置中心**:动态配置、热更新、多租户支持
- 💰 **支付集成**:微信支付、支付宝、线下支付
- 📱 **多渠道支持**微信、小程序、H5、APP
- 🔐 **多租户架构**SaaS/独立版混合部署
- 📊 **监控告警**:日志、指标、链路追踪
- 🛠️ **开发工具**:代码生成器、插件系统
## 🚀 快速开始
### 环境要求
- Node.js 18+
- MySQL 8.0+
- Redis 6.0+
### 安装运行
```bash
# 1. 克隆项目
git clone <repository-url>
cd wwjcloud-nest
# 2. 安装依赖
npm install
# 3. 启动数据库 (Docker)
docker-compose up -d mysql redis
# 4. 启动应用
npm run start
# 5. 访问应用
http://localhost:3001
```
### API测试
```bash
# 健康检查
curl http://localhost:3001/
# 配置状态
curl http://localhost:3001/config/status
# 查询配置
curl http://localhost:3001/config/value/WECHAT
```
## 📁 项目结构
```
src/
├── config/ # 配置中心
├── common/ # 基础设施
│ ├── cache/ # 缓存服务
│ ├── logging/ # 日志服务
│ ├── monitoring/ # 监控服务
│ ├── queue/ # 队列服务
│ ├── utils/ # 工具类
│ └── ...
├── vendor/ # 第三方集成
│ ├── pay/ # 支付服务
│ ├── sms/ # 短信服务
│ ├── upload/ # 上传服务
│ └── ...
├── core/ # 通用业务
└── main.ts # 应用入口
```
## 🏪 技术栈
### 后端技术
- **框架**: NestJS 11 + TypeScript
- **数据库**: MySQL 8.0 + TypeORM
- **缓存**: Redis + BullMQ队列
- **文档**: Swagger API文档
- **监控**: Prometheus + OpenTelemetry
### 开发工具
- **构建**: Nest CLI + Webpack
- **代码质量**: ESLint + Prettier
- **测试**: Jest + Supertest
- **容器**: Docker + Docker Compose
## 🌟 对标说明
| 特性 | Java Spring Boot | PHP ThinkPHP | WWJCloud NestJS |
|-----|------------------|--------------|-----------------|
| 依赖注入 | ✅ Spring IoC | ✅ Container | ✅ NestJS DI |
| 配置管理 | ✅ Application.yml | ✅ Config | ✅ ConfigCenter |
| 数据库ORM | ✅ JPA/MyBatis | ✅ Model | ✅ TypeORM |
| 缓存支持 | ✅ Redisson | ✅ Cache | ✅ Redis |
| 队列系统 | ✅ Rabbit/Active | ✅ Queue | ✅ BullMQ |
| 监控告警 | ✅ Micrometer | ✅ Monitor | ✅ Prometheus |
## 📖 开发文档
- [架构设计文档](./ARCHITECTURE.md)
- [迁移指南](./MIGRATION_GUIDE.md)
- [开发计划](./DEVELOPMENT_PLAN.md)
## 🤝 贡献指南
1. Fork 项目
2. 创建特性分支 (`git checkout -b feature/amazing-feature`)
3. 提交更改 (`git commit -m 'Add amazing feature'`)
4. 推送到分支 (`git push origin feature/amazing-feature`)
5. 创建 Pull Request
## 📄 许可证
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。
## 👥 团队
- **架构师**: WWJCloud团队
- **开发者**: NestJS企业级开发团队
- **产品经理**: SaaS平台产品团队
---
⭐ 如果这个项目对你有帮助,请给它一个星星!

View File

@@ -1,15 +0,0 @@
node_modules
dist
npm-debug.log
.env.local
.env.*.local
.git
.gitignore
.vscode
.idea
*.md
!README.md
test
coverage
.cache

View File

@@ -1,11 +0,0 @@
# NestJS后端API地址
VITE_APP_BASE_URL=http://localhost:3000
# 开发模式
NODE_ENV=development
# API请求超时毫秒
VITE_APP_TIMEOUT=30000
# 是否开启Mock数据
VITE_APP_MOCK=false

View File

@@ -1,11 +0,0 @@
# NestJS后端API地址生产环境
VITE_APP_BASE_URL=http://localhost:3000
# 生产模式
NODE_ENV=production
# API请求超时毫秒
VITE_APP_TIMEOUT=30000
# 是否开启Mock数据
VITE_APP_MOCK=false

View File

@@ -1,28 +0,0 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:vue/vue3-essential",
"standard-with-typescript",
"eslint:recommended"
],
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module",
"parser": "@typescript-eslint/parser"
},
"plugins": [
"vue",
"@typescript-eslint"
],
"rules": {
"no-tabs":"off",
"indent": [1, 4, { "SwitchCase": 1 }],
"eqeqeq":"off",
"vue/multi-word-component-names": "off"
}
}

View File

@@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -1,40 +0,0 @@
# ========================================
# Admin Frontend Dockerfile
# ========================================
FROM node:20-alpine AS builder
WORKDIR /app
# 复制package文件
COPY package*.json ./
# 安装依赖
RUN npm ci && npm cache clean --force
# 复制源码
COPY . .
# 构建应用
RUN npm run build
# ========================================
# Production Stage (Nginx)
# ========================================
FROM nginx:alpine
# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制Nginx配置
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 暴露端口
EXPOSE 80
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget --quiet --tries=1 --spider http://localhost/ || exit 1
# 启动Nginx
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -1,18 +0,0 @@
# Vue 3 + TypeScript + Vite
This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support For `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1. Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2. Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.

View File

@@ -1,7 +0,0 @@
// Generated by 'unplugin-auto-import'
export {}
declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const ElNotification: typeof import('element-plus/es')['ElNotification']
}

View File

@@ -1,107 +0,0 @@
// generated by unplugin-vue-components
// We suggest you to commit this file into source control
// Read more: https://github.com/vuejs/core/pull/3399
import '@vue/runtime-core'
export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
Attachment: typeof import('./src/components/upload-attachment/attachment.vue')['default']
DiyLink: typeof import('./src/components/diy-link/index.vue')['default']
DiyPage: typeof import('./src/components/diy-page/index.vue')['default']
Editor: typeof import('./src/components/editor/index.vue')['default']
ElAlert: typeof import('element-plus/es')['ElAlert']
ElAside: typeof import('element-plus/es')['ElAside']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCarousel: typeof import('element-plus/es')['ElCarousel']
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElContainer: typeof import('element-plus/es')['ElContainer']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
ElEmpty: typeof import('element-plus/es')['ElEmpty']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElImage: typeof import('element-plus/es')['ElImage']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMain: typeof import('element-plus/es')['ElMain']
ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElOptionGroup: typeof import('element-plus/es')['ElOptionGroup']
ElPageHeader: typeof import('element-plus/es')['ElPageHeader']
ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElResult: typeof import('element-plus/es')['ElResult']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSlider: typeof import('element-plus/es')['ElSlider']
ElStatistic: typeof import('element-plus/es')['ElStatistic']
ElStep: typeof import('element-plus/es')['ElStep']
ElSteps: typeof import('element-plus/es')['ElSteps']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTimeline: typeof import('element-plus/es')['ElTimeline']
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
ExportSure: typeof import('./src/components/export-sure/index.vue')['default']
HeatMap: typeof import('./src/components/heat-map/index.vue')['default']
Icon: typeof import('./src/components/icon/index.vue')['default']
Markdown: typeof import('./src/components/markdown/index.vue')['default']
PopoverInput: typeof import('./src/components/popover-input/index.vue')['default']
RangeInput: typeof import('./src/components/range-input/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SelectArea: typeof import('./src/components/select-area/index.vue')['default']
SelectIcon: typeof import('./src/components/select-icon/index.vue')['default']
SpreadPopup: typeof import('./src/components/spread-popup/index.vue')['default']
UploadAttachment: typeof import('./src/components/upload-attachment/index.vue')['default']
UploadAudio: typeof import('./src/components/upload-audio/index.vue')['default']
UploadFile: typeof import('./src/components/upload-file/index.vue')['default']
UploadImage: typeof import('./src/components/upload-image/index.vue')['default']
UploadVideo: typeof import('./src/components/upload-video/index.vue')['default']
Verify: typeof import('./src/components/verifition/Verify.vue')['default']
VerifyPoints: typeof import('./src/components/verifition/Verify/VerifyPoints.vue')['default']
VerifySlide: typeof import('./src/components/verifition/Verify/VerifySlide.vue')['default']
VideoPlayer: typeof import('./src/components/video-player/index.vue')['default']
}
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
}

View File

@@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image" href="/niucloud.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -1,45 +0,0 @@
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript;
# Vue Router History模式支持
location / {
try_files $uri $uri/ /index.html;
}
# API代理到NestJS后端
location /adminapi/ {
proxy_pass http://nestjs-backend:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 7d;
add_header Cache-Control "public, immutable";
}
# 安全headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}

View File

@@ -1,59 +0,0 @@
{
"name": "admin",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build && node publish.cjs",
"preview": "vite preview"
},
"dependencies": {
"@element-plus/icons-vue": "2.0.10",
"@highlightjs/vue-plugin": "2.1.0",
"@types/lodash-es": "4.17.6",
"@vueuse/core": "9.12.0",
"axios": "1.4.0",
"crypto-js": "4.1.1",
"css-color-function": "1.3.3",
"day": "^0.0.2",
"echarts": "5.4.1",
"element-plus": "^2.7.4",
"highlight.js": "11.0.1",
"lodash-es": "4.17.21",
"nprogress": "0.2.0",
"pinia": "2.0.30",
"qrcode": "1.5.1",
"sass": "1.58.0",
"sortablejs": "1.15.0",
"vditor": "^3.10.9",
"vue": "3.2.45",
"vue-i18n": "9.2.2",
"vue-jsonp": "2.0.0",
"vue-router": "4.1.6",
"vue-ueditor-wrap": "^3.0.8",
"vue-web-terminal": "3.2.2",
"vue3-video-play": "1.3.1-beta.6"
},
"devDependencies": {
"@tailwindcss/line-clamp": "0.4.2",
"@types/qrcode": "1.5.0",
"@types/sortablejs": "1.15.0",
"@typescript-eslint/eslint-plugin": "5.53.0",
"@vitejs/plugin-vue": "4.0.0",
"autoprefixer": "10.4.13",
"eslint": "8.34.0",
"eslint-config-standard-with-typescript": "34.0.0",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-n": "15.6.1",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-vue": "9.9.0",
"postcss": "8.4.21",
"tailwindcss": "3.2.4",
"typescript": "4.9.5",
"unplugin-auto-import": "0.13.0",
"unplugin-vue-components": "0.23.0",
"vite": "4.1.0",
"vue-tsc": "1.0.24"
}
}

View File

@@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,62 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<style type="text/css">
* {
color: #838383;
margin: 0;
padding: 0
}
html, body {
font-size: 12px;
overflow: hidden;
}
.content {
padding: 5px 0 0 15px;
}
input {
margin-left: 4px;
box-sizing: border-box;
width: 210px;
height: 30px;
line-height: 30px;
border: 1px solid #d7d7d7;
border-radius: 3px;
padding: 0 5px;
outline: none;
}
</style>
</head>
<body>
<div class="content">
<span><var id="lang_input_anchorName"></var></span><input id="anchorName" value=""/>
</div>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<script type="text/javascript">
var anchorInput = $G('anchorName'),
node = editor.selection.getRange().getClosedNode();
if (node && node.tagName == 'IMG' && (node = node.getAttribute('anchorname'))) {
anchorInput.value = node;
}
anchorInput.onkeydown = function (evt) {
evt = evt || window.event;
if (evt.keyCode == 13) {
editor.execCommand('anchor', anchorInput.value);
dialog.close();
domUtils.preventDefault(evt)
}
};
dialog.onok = function () {
editor.execCommand('anchor', anchorInput.value);
dialog.close();
};
$focus(anchorInput);
</script>
</body>
</html>

View File

@@ -1,716 +0,0 @@
@charset "utf-8";
/* dialog样式 */
.wrapper {
zoom: 1;
width: 630px;
*width: 626px;
height: 380px;
margin: 0 auto;
padding: 10px;
position: relative;
font-family: sans-serif;
}
/*tab样式框大小*/
.tabhead {
float: left;
}
.tabbody {
width: 100%;
height: 346px;
position: relative;
clear: both;
}
.tabbody .panel {
position: absolute;
width: 0;
height: 0;
background: #fff;
overflow: hidden;
display: none;
}
.tabbody .panel.focus {
width: 100%;
height: 346px;
display: block;
}
/* 上传附件 */
.tabbody #upload.panel {
width: 0;
height: 0;
overflow: hidden;
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
background: #fff;
display: block;
}
.tabbody #upload.panel.focus {
width: 100%;
height: 346px;
display: block;
clip: auto;
}
#upload .queueList {
margin: 0;
width: 100%;
height: 100%;
position: absolute;
overflow: hidden;
}
#upload p {
margin: 0;
}
.element-invisible {
width: 0 !important;
height: 0 !important;
border: 0;
padding: 0;
margin: 0;
overflow: hidden;
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
}
#upload .placeholder {
margin: 10px;
border: 2px dashed #e6e6e6;
*border: 0px dashed #e6e6e6;
height: 172px;
padding-top: 150px;
text-align: center;
background: url(./images/image.png) center 70px no-repeat;
color: #cccccc;
font-size: 18px;
position: relative;
top: 0;
*top: 10px;
}
#upload .placeholder .webuploader-pick {
font-size: 18px;
background: #00b7ee;
border-radius: 3px;
line-height: 44px;
padding: 0 30px;
*width: 120px;
color: #fff;
display: inline-block;
margin: 0 auto 20px auto;
cursor: pointer;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
#upload .placeholder .webuploader-pick-hover {
background: #00a2d4;
}
#filePickerContainer {
text-align: center;
}
#upload .placeholder .flashTip {
color: #666666;
font-size: 12px;
position: absolute;
width: 100%;
text-align: center;
bottom: 20px;
}
#upload .placeholder .flashTip a {
color: #0785d1;
text-decoration: none;
}
#upload .placeholder .flashTip a:hover {
text-decoration: underline;
}
#upload .placeholder.webuploader-dnd-over {
border-color: #999999;
}
#upload .filelist {
list-style: none;
margin: 0;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
position: relative;
height: 300px;
}
#upload .filelist:after {
content: '';
display: block;
width: 0;
height: 0;
overflow: hidden;
clear: both;
}
#upload .filelist li {
width: 113px;
height: 113px;
background: url(./images/bg.png);
text-align: center;
margin: 9px 0 0 9px;
*margin: 6px 0 0 6px;
position: relative;
display: block;
float: left;
overflow: hidden;
font-size: 12px;
}
#upload .filelist li p.log {
position: relative;
top: -45px;
}
#upload .filelist li p.title {
position: absolute;
top: 0;
left: 0;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
top: 5px;
text-indent: 5px;
text-align: left;
}
#upload .filelist li p.progress {
position: absolute;
width: 100%;
bottom: 0;
left: 0;
height: 8px;
overflow: hidden;
z-index: 50;
margin: 0;
border-radius: 0;
background: none;
-webkit-box-shadow: 0 0 0;
}
#upload .filelist li p.progress span {
display: none;
overflow: hidden;
width: 0;
height: 100%;
background: #1483d8 url(./images/progress.png) repeat-x;
-webit-transition: width 200ms linear;
-moz-transition: width 200ms linear;
-o-transition: width 200ms linear;
-ms-transition: width 200ms linear;
transition: width 200ms linear;
-webkit-animation: progressmove 2s linear infinite;
-moz-animation: progressmove 2s linear infinite;
-o-animation: progressmove 2s linear infinite;
-ms-animation: progressmove 2s linear infinite;
animation: progressmove 2s linear infinite;
-webkit-transform: translateZ(0);
}
@-webkit-keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
@-moz-keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
@keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
#upload .filelist li p.imgWrap {
position: relative;
z-index: 2;
line-height: 113px;
vertical-align: middle;
overflow: hidden;
width: 113px;
height: 113px;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webit-transition: 200ms ease-out;
-moz-transition: 200ms ease-out;
-o-transition: 200ms ease-out;
-ms-transition: 200ms ease-out;
transition: 200ms ease-out;
}
#upload .filelist li p.imgWrap.notimage {
margin-top: 0;
width: 111px;
height: 111px;
border: 1px #eeeeee solid;
}
#upload .filelist li p.imgWrap.notimage i.file-preview {
margin-top: 15px;
}
#upload .filelist li img {
width: 100%;
}
#upload .filelist li p.error {
background: #f43838;
color: #fff;
position: absolute;
bottom: 0;
left: 0;
height: 28px;
line-height: 28px;
width: 100%;
z-index: 100;
display: none;
}
#upload .filelist li .success {
display: block;
position: absolute;
left: 0;
bottom: 0;
height: 40px;
width: 100%;
z-index: 200;
background: url(./images/success.png) no-repeat right bottom;
background-image: url(./images/success.gif) \9;
}
#upload .filelist li.filePickerBlock {
width: 113px;
height: 113px;
background: url(./images/image.png) no-repeat center 12px;
border: 1px solid #eeeeee;
border-radius: 0;
}
#upload .filelist li.filePickerBlock div.webuploader-pick {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
opacity: 0;
background: none;
font-size: 0;
}
#upload .filelist div.file-panel {
position: absolute;
height: 0;
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#80000000', endColorstr='#80000000') \0;
background: rgba(0, 0, 0, 0.5);
width: 100%;
top: 0;
left: 0;
overflow: hidden;
z-index: 300;
}
#upload .filelist div.file-panel span {
width: 24px;
height: 24px;
display: inline;
float: right;
text-indent: -9999px;
overflow: hidden;
background: url(./images/icons.png) no-repeat;
background: url(./images/icons.gif) no-repeat \9;
margin: 5px 1px 1px;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#upload .filelist div.file-panel span.rotateLeft {
display: none;
background-position: 0 -24px;
}
#upload .filelist div.file-panel span.rotateLeft:hover {
background-position: 0 0;
}
#upload .filelist div.file-panel span.rotateRight {
display: none;
background-position: -24px -24px;
}
#upload .filelist div.file-panel span.rotateRight:hover {
background-position: -24px 0;
}
#upload .filelist div.file-panel span.cancel {
background-position: -48px -24px;
}
#upload .filelist div.file-panel span.cancel:hover {
background-position: -48px 0;
}
#upload .statusBar {
height: 45px;
border-bottom: 1px solid #dadada;
margin: 0 10px;
padding: 0;
line-height: 45px;
vertical-align: middle;
position: relative;
}
#upload .statusBar .progress {
border: 1px solid #1483d8;
width: 198px;
background: #fff;
height: 18px;
position: absolute;
top: 12px;
display: none;
text-align: center;
line-height: 18px;
color: #6dbfff;
margin: 0 10px 0 0;
}
#upload .statusBar .progress span.percentage {
width: 0;
height: 100%;
left: 0;
top: 0;
background: #1483d8;
position: absolute;
}
#upload .statusBar .progress span.text {
position: relative;
z-index: 10;
}
#upload .statusBar .info {
display: inline-block;
font-size: 14px;
color: #666666;
}
#upload .statusBar .btns {
position: absolute;
top: 7px;
right: 0;
line-height: 30px;
}
#filePickerBtn {
display: inline-block;
float: left;
}
#upload .statusBar .btns .webuploader-pick,
#upload .statusBar .btns .uploadBtn,
#upload .statusBar .btns .uploadBtn.state-uploading,
#upload .statusBar .btns .uploadBtn.state-paused {
background: #ffffff;
border: 1px solid #cfcfcf;
color: #565656;
padding: 0 18px;
display: inline-block;
border-radius: 3px;
margin-left: 10px;
cursor: pointer;
font-size: 14px;
float: left;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#upload .statusBar .btns .webuploader-pick-hover,
#upload .statusBar .btns .uploadBtn:hover,
#upload .statusBar .btns .uploadBtn.state-uploading:hover,
#upload .statusBar .btns .uploadBtn.state-paused:hover {
background: #f0f0f0;
}
#upload .statusBar .btns .uploadBtn,
#upload .statusBar .btns .uploadBtn.state-paused {
background: #00b7ee;
color: #fff;
border-color: transparent;
}
#upload .statusBar .btns .uploadBtn:hover,
#upload .statusBar .btns .uploadBtn.state-paused:hover {
background: #00a2d4;
}
#upload .statusBar .btns .uploadBtn.disabled {
pointer-events: none;
filter: alpha(opacity=60);
-moz-opacity: 0.6;
-khtml-opacity: 0.6;
opacity: 0.6;
}
/* 图片管理样式 */
#online {
width: 100%;
height: 336px;
padding: 10px 0 0 0;
}
#online #fileList {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
position: relative;
}
#online ul {
display: block;
list-style: none;
margin: 0;
padding: 0;
}
#online li {
float: left;
display: block;
list-style: none;
padding: 0;
width: 113px;
height: 113px;
margin: 0 0 9px 9px;
*margin: 0 0 6px 6px;
background-color: #eee;
overflow: hidden;
cursor: pointer;
position: relative;
}
#online li.clearFloat {
float: none;
clear: both;
display: block;
width: 0;
height: 0;
margin: 0;
padding: 0;
}
#online li img {
cursor: pointer;
}
#online li div.file-wrapper {
cursor: pointer;
position: absolute;
display: block;
width: 111px;
height: 111px;
border: 1px solid #eee;
background: url("./images/bg.png") repeat;
}
#online li div span.file-title {
display: block;
padding: 0 3px;
margin: 3px 0 0 0;
font-size: 12px;
height: 15px;
color: #555555;
text-align: center;
width: 107px;
white-space: nowrap;
word-break: break-all;
overflow: hidden;
text-overflow: ellipsis;
}
#online li .icon {
cursor: pointer;
width: 113px;
height: 113px;
position: absolute;
top: 0;
left: 0;
z-index: 2;
border: 0;
background-repeat: no-repeat;
}
#online li .icon:hover {
width: 107px;
height: 107px;
border: 3px solid #1094fa;
}
#online li.selected .icon {
background-image: url(images/success.png);
background-image: url(images/success.gif) \9;
background-position: 75px 75px;
}
#online li.selected .icon:hover {
width: 107px;
height: 107px;
border: 3px solid #1094fa;
background-position: 72px 72px;
}
/* 在线文件的文件预览图标 */
i.file-preview {
display: block;
margin: 10px auto;
width: 70px;
height: 70px;
background-image: url("./images/file-icons.png");
background-image: url("./images/file-icons.gif") \9;
background-position: -140px center;
background-repeat: no-repeat;
}
i.file-preview.file-type-dir {
background-position: 0 center;
}
i.file-preview.file-type-file {
background-position: -140px center;
}
i.file-preview.file-type-filelist {
background-position: -210px center;
}
i.file-preview.file-type-zip,
i.file-preview.file-type-rar,
i.file-preview.file-type-7z,
i.file-preview.file-type-tar,
i.file-preview.file-type-gz,
i.file-preview.file-type-bz2 {
background-position: -280px center;
}
i.file-preview.file-type-xls,
i.file-preview.file-type-xlsx {
background-position: -350px center;
}
i.file-preview.file-type-doc,
i.file-preview.file-type-docx {
background-position: -420px center;
}
i.file-preview.file-type-ppt,
i.file-preview.file-type-pptx {
background-position: -490px center;
}
i.file-preview.file-type-vsd {
background-position: -560px center;
}
i.file-preview.file-type-pdf {
background-position: -630px center;
}
i.file-preview.file-type-txt,
i.file-preview.file-type-md,
i.file-preview.file-type-json,
i.file-preview.file-type-htm,
i.file-preview.file-type-xml,
i.file-preview.file-type-html,
i.file-preview.file-type-js,
i.file-preview.file-type-css,
i.file-preview.file-type-php,
i.file-preview.file-type-jsp,
i.file-preview.file-type-asp {
background-position: -700px center;
}
i.file-preview.file-type-apk {
background-position: -770px center;
}
i.file-preview.file-type-exe {
background-position: -840px center;
}
i.file-preview.file-type-ipa {
background-position: -910px center;
}
i.file-preview.file-type-mp4,
i.file-preview.file-type-swf,
i.file-preview.file-type-mkv,
i.file-preview.file-type-avi,
i.file-preview.file-type-flv,
i.file-preview.file-type-mov,
i.file-preview.file-type-mpg,
i.file-preview.file-type-mpeg,
i.file-preview.file-type-ogv,
i.file-preview.file-type-webm,
i.file-preview.file-type-rm,
i.file-preview.file-type-rmvb {
background-position: -980px center;
}
i.file-preview.file-type-ogg,
i.file-preview.file-type-wav,
i.file-preview.file-type-wmv,
i.file-preview.file-type-mid,
i.file-preview.file-type-mp3 {
background-position: -1050px center;
}
i.file-preview.file-type-jpg,
i.file-preview.file-type-jpeg,
i.file-preview.file-type-gif,
i.file-preview.file-type-bmp,
i.file-preview.file-type-png,
i.file-preview.file-type-psd {
background-position: -140px center;
}

View File

@@ -1,61 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>ueditor图片对话框</title>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<!-- jquery -->
<script type="text/javascript" src="../../third-party/jquery-1.10.2.js?628072e7"></script>
<!-- webuploader -->
<script src="../../third-party/webuploader/webuploader.js?f37088cc"></script>
<link rel="stylesheet" type="text/css" href="../../third-party/webuploader/webuploader.css?0057c5c7">
<!-- attachment dialog -->
<link rel="stylesheet" href="attachment.css?e8f09700" type="text/css"/>
</head>
<body>
<div class="wrapper">
<div id="tabhead" class="tabhead">
<span class="tab focus" data-content-id="upload"><var id="lang_tab_upload"></var></span>
<span class="tab" data-content-id="online"><var id="lang_tab_online"></var></span>
</div>
<div id="tabbody" class="tabbody">
<!-- 上传图片 -->
<div id="upload" class="panel focus">
<div id="queueList" class="queueList">
<div class="statusBar element-invisible">
<div class="progress">
<span class="text">0%</span>
<span class="percentage"></span>
</div>
<div class="info"></div>
<div class="btns">
<div id="filePickerBtn"></div>
<div class="uploadBtn"><var id="lang_start_upload"></var></div>
</div>
</div>
<div id="dndArea" class="placeholder">
<div class="filePickerContainer">
<div id="filePickerReady"></div>
</div>
</div>
<ul class="filelist element-invisible">
<li id="filePickerBlock" class="filePickerBlock"></li>
</ul>
</div>
</div>
<!-- 在线图片 -->
<div id="online" class="panel">
<div id="fileList"><var id="lang_imgLoading"></var></div>
</div>
</div>
</div>
<script type="text/javascript" src="attachment.js?21e4194b"></script>
</body>
</html>

View File

@@ -1,774 +0,0 @@
/**
* User: Jinqn
* Date: 14-04-08
* Time: 下午16:34
* 上传图片对话框逻辑代码,包括tab: 远程图片/上传图片/在线图片/搜索图片
*/
(function () {
var uploadFile,
onlineFile;
window.onload = function () {
initTabs();
initButtons();
};
/* 初始化tab标签 */
function initTabs() {
var tabs = $G('tabhead').children;
for (var i = 0; i < tabs.length; i++) {
domUtils.on(tabs[i], "click", function (e) {
var target = e.target || e.srcElement;
setTabFocus(target.getAttribute('data-content-id'));
});
}
setTabFocus('upload');
}
/* 初始化tabbody */
function setTabFocus(id) {
if (!id) return;
var i, bodyId, tabs = $G('tabhead').children;
for (i = 0; i < tabs.length; i++) {
bodyId = tabs[i].getAttribute('data-content-id')
if (bodyId == id) {
domUtils.addClass(tabs[i], 'focus');
domUtils.addClass($G(bodyId), 'focus');
} else {
domUtils.removeClasses(tabs[i], 'focus');
domUtils.removeClasses($G(bodyId), 'focus');
}
}
switch (id) {
case 'upload':
uploadFile = uploadFile || new UploadFile('queueList');
break;
case 'online':
onlineFile = onlineFile || new OnlineFile('fileList');
break;
}
}
/* 初始化onok事件 */
function initButtons() {
dialog.onok = function () {
var list = [], id, tabs = $G('tabhead').children;
for (var i = 0; i < tabs.length; i++) {
if (domUtils.hasClass(tabs[i], 'focus')) {
id = tabs[i].getAttribute('data-content-id');
break;
}
}
switch (id) {
case 'upload':
list = uploadFile.getInsertList();
var count = uploadFile.getQueueCount();
if (count) {
$('.info', '#queueList').html('<span style="color:red;">' + '还有2个未上传文件'.replace(/[\d]/, count) + '</span>');
return false;
}
break;
case 'online':
list = onlineFile.getInsertList();
break;
}
editor.execCommand('insertfile', list);
};
}
/* 上传附件 */
function UploadFile(target) {
this.$wrap = target.constructor == String ? $('#' + target) : $(target);
this.init();
}
UploadFile.prototype = {
init: function () {
this.fileList = [];
this.initContainer();
this.initUploader();
},
initContainer: function () {
this.$queue = this.$wrap.find('.filelist');
},
/* 初始化容器 */
initUploader: function () {
var _this = this,
$ = jQuery, // just in case. Make sure it's not an other libaray.
$wrap = _this.$wrap,
// 图片容器
$queue = $wrap.find('.filelist'),
// 状态栏,包括进度和控制按钮
$statusBar = $wrap.find('.statusBar'),
// 文件总体选择信息。
$info = $statusBar.find('.info'),
// 上传按钮
$upload = $wrap.find('.uploadBtn'),
// 上传按钮
$filePickerBtn = $wrap.find('.filePickerBtn'),
// 上传按钮
$filePickerBlock = $wrap.find('.filePickerBlock'),
// 没选择文件之前的内容。
$placeHolder = $wrap.find('.placeholder'),
// 总体进度条
$progress = $statusBar.find('.progress').hide(),
// 添加的文件数量
fileCount = 0,
// 添加的文件总大小
fileSize = 0,
// 优化retina, 在retina下这个值是2
ratio = window.devicePixelRatio || 1,
// 缩略图大小
thumbnailWidth = 113 * ratio,
thumbnailHeight = 113 * ratio,
// 可能有pedding, ready, uploading, confirm, done.
state = '',
// 所有文件的进度信息key为file id
percentages = {},
supportTransition = (function () {
var s = document.createElement('p').style,
r = 'transition' in s ||
'WebkitTransition' in s ||
'MozTransition' in s ||
'msTransition' in s ||
'OTransition' in s;
s = null;
return r;
})(),
// WebUploader实例
uploader,
actionUrl = editor.getActionUrl(editor.getOpt('fileActionName')),
fileMaxSize = editor.getOpt('fileMaxSize'),
acceptExtensions = (editor.getOpt('fileAllowFiles') || []).join('').replace(/\./g, ',').replace(/^[,]/, '');
;
if (!WebUploader.Uploader.support()) {
$('#filePickerReady').after($('<div>').html(lang.errorNotSupport)).hide();
return;
} else if (!editor.getOpt('fileActionName')) {
$('#filePickerReady').after($('<div>').html(lang.errorLoadConfig)).hide();
return;
}
uploader = _this.uploader = WebUploader.create({
pick: {
id: '#filePickerReady',
label: lang.uploadSelectFile
},
swf: '../../third-party/webuploader/Uploader.swf',
server: actionUrl,
fileVal: editor.getOpt('fileFieldName'),
duplicate: true,
fileSingleSizeLimit: fileMaxSize,
headers: editor.getOpt('serverHeaders') || {},
compress: false
});
uploader.addButton({
id: '#filePickerBlock'
});
uploader.addButton({
id: '#filePickerBtn',
label: lang.uploadAddFile
});
setState('pedding');
// 当有文件添加进来时执行负责view的创建
function addFile(file) {
var $li = $('<li id="' + file.id + '">' +
'<p class="title">' + file.name + '</p>' +
'<p class="imgWrap"></p>' +
'<p class="progress"><span></span></p>' +
'</li>'),
$btns = $('<div class="file-panel">' +
'<span class="cancel">' + lang.uploadDelete + '</span>' +
'<span class="rotateRight">' + lang.uploadTurnRight + '</span>' +
'<span class="rotateLeft">' + lang.uploadTurnLeft + '</span></div>').appendTo($li),
$prgress = $li.find('p.progress span'),
$wrap = $li.find('p.imgWrap'),
$info = $('<p class="error"></p>').hide().appendTo($li),
showError = function (code) {
switch (code) {
case 'exceed_size':
text = lang.errorExceedSize;
break;
case 'interrupt':
text = lang.errorInterrupt;
break;
case 'http':
text = lang.errorHttp;
break;
case 'not_allow_type':
text = lang.errorFileType;
break;
default:
text = lang.errorUploadRetry;
break;
}
$info.text(text).show();
};
if (file.getStatus() === 'invalid') {
showError(file.statusText);
} else {
$wrap.text(lang.uploadPreview);
if ('|png|jpg|jpeg|bmp|gif|'.indexOf('|' + file.ext.toLowerCase() + '|') == -1) {
$wrap.empty().addClass('notimage').append('<i class="file-preview file-type-' + file.ext.toLowerCase() + '"></i>' +
'<span class="file-title" title="' + file.name + '">' + file.name + '</span>');
} else {
if (browser.ie && browser.version <= 7) {
$wrap.text(lang.uploadNoPreview);
} else {
uploader.makeThumb(file, function (error, src) {
if (error || !src) {
$wrap.text(lang.uploadNoPreview);
} else {
var $img = $('<img src="' + src + '">');
$wrap.empty().append($img);
$img.on('error', function () {
$wrap.text(lang.uploadNoPreview);
});
}
}, thumbnailWidth, thumbnailHeight);
}
}
percentages[file.id] = [file.size, 0];
file.rotation = 0;
/* 检查文件格式 */
if (!file.ext || acceptExtensions.indexOf(file.ext.toLowerCase()) == -1) {
showError('not_allow_type');
uploader.removeFile(file);
}
}
file.on('statuschange', function (cur, prev) {
if (prev === 'progress') {
$prgress.hide().width(0);
} else if (prev === 'queued') {
$li.off('mouseenter mouseleave');
$btns.remove();
}
// 成功
if (cur === 'error' || cur === 'invalid') {
showError(file.statusText);
percentages[file.id][1] = 1;
} else if (cur === 'interrupt') {
showError('interrupt');
} else if (cur === 'queued') {
percentages[file.id][1] = 0;
} else if (cur === 'progress') {
$info.hide();
$prgress.css('display', 'block');
} else if (cur === 'complete') {
}
$li.removeClass('state-' + prev).addClass('state-' + cur);
});
$li.on('mouseenter', function () {
$btns.stop().animate({height: 30});
});
$li.on('mouseleave', function () {
$btns.stop().animate({height: 0});
});
$btns.on('click', 'span', function () {
var index = $(this).index(),
deg;
switch (index) {
case 0:
uploader.removeFile(file);
return;
case 1:
file.rotation += 90;
break;
case 2:
file.rotation -= 90;
break;
}
if (supportTransition) {
deg = 'rotate(' + file.rotation + 'deg)';
$wrap.css({
'-webkit-transform': deg,
'-mos-transform': deg,
'-o-transform': deg,
'transform': deg
});
} else {
$wrap.css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (~~((file.rotation / 90) % 4 + 4) % 4) + ')');
}
});
$li.insertBefore($filePickerBlock);
}
// 负责view的销毁
function removeFile(file) {
var $li = $('#' + file.id);
delete percentages[file.id];
updateTotalProgress();
$li.off().find('.file-panel').off().end().remove();
}
function updateTotalProgress() {
var loaded = 0,
total = 0,
spans = $progress.children(),
percent;
$.each(percentages, function (k, v) {
total += v[0];
loaded += v[0] * v[1];
});
percent = total ? loaded / total : 0;
spans.eq(0).text(Math.round(percent * 100) + '%');
spans.eq(1).css('width', Math.round(percent * 100) + '%');
updateStatus();
}
function setState(val, files) {
if (val != state) {
var stats = uploader.getStats();
$upload.removeClass('state-' + state);
$upload.addClass('state-' + val);
switch (val) {
/* 未选择文件 */
case 'pedding':
$queue.addClass('element-invisible');
$statusBar.addClass('element-invisible');
$placeHolder.removeClass('element-invisible');
$progress.hide();
$info.hide();
uploader.refresh();
break;
/* 可以开始上传 */
case 'ready':
$placeHolder.addClass('element-invisible');
$queue.removeClass('element-invisible');
$statusBar.removeClass('element-invisible');
$progress.hide();
$info.show();
$upload.text(lang.uploadStart);
uploader.refresh();
break;
/* 上传中 */
case 'uploading':
$progress.show();
$info.hide();
$upload.text(lang.uploadPause);
break;
/* 暂停上传 */
case 'paused':
$progress.show();
$info.hide();
$upload.text(lang.uploadContinue);
break;
case 'confirm':
$progress.show();
$info.hide();
$upload.text(lang.uploadStart);
stats = uploader.getStats();
if (stats.successNum && !stats.uploadFailNum) {
setState('finish');
return;
}
break;
case 'finish':
$progress.hide();
$info.show();
if (stats.uploadFailNum) {
$upload.text(lang.uploadRetry);
} else {
$upload.text(lang.uploadStart);
}
break;
}
state = val;
updateStatus();
}
if (!_this.getQueueCount()) {
$upload.addClass('disabled')
} else {
$upload.removeClass('disabled')
}
}
function updateStatus() {
var text = '', stats;
if (state === 'ready') {
text = lang.updateStatusReady.replace('_', fileCount).replace('_KB', WebUploader.formatSize(fileSize));
} else if (state === 'confirm') {
stats = uploader.getStats();
if (stats.uploadFailNum) {
text = lang.updateStatusConfirm.replace('_', stats.successNum).replace('_', stats.successNum);
}
} else {
stats = uploader.getStats();
text = lang.updateStatusFinish.replace('_', fileCount).replace('_KB', WebUploader.formatSize(fileSize)).replace('_', stats.successNum);
if (stats.uploadFailNum) {
text += lang.updateStatusError.replace('_', stats.uploadFailNum);
}
}
$info.html(text);
}
uploader.on('fileQueued', function (file) {
if (file.ext && acceptExtensions.indexOf(file.ext.toLowerCase()) != -1 && file.size <= fileMaxSize) {
fileCount++;
fileSize += file.size;
}
if (fileCount === 1) {
$placeHolder.addClass('element-invisible');
$statusBar.show();
}
addFile(file);
});
uploader.on('fileDequeued', function (file) {
if (file.ext && acceptExtensions.indexOf(file.ext.toLowerCase()) != -1 && file.size <= fileMaxSize) {
fileCount--;
fileSize -= file.size;
}
removeFile(file);
updateTotalProgress();
});
uploader.on('filesQueued', function (file) {
if (!uploader.isInProgress() && (state == 'pedding' || state == 'finish' || state == 'confirm' || state == 'ready')) {
setState('ready');
}
updateTotalProgress();
});
uploader.on('all', function (type, files) {
switch (type) {
case 'uploadFinished':
setState('confirm', files);
break;
case 'startUpload':
/* 添加额外的GET参数 */
var params = utils.serializeParam(editor.queryCommandValue('serverparam')) || '',
url = utils.formatUrl(actionUrl + (actionUrl.indexOf('?') == -1 ? '?' : '&') + 'encode=utf-8&' + params);
uploader.option('server', url);
setState('uploading', files);
break;
case 'stopUpload':
setState('paused', files);
break;
}
});
uploader.on('uploadBeforeSend', function (file, data, header) {
//这里可以通过data对象添加POST参数
if (actionUrl.toLowerCase().indexOf('jsp') != -1) {
header['X_Requested_With'] = 'XMLHttpRequest';
}
});
uploader.on('uploadProgress', function (file, percentage) {
var $li = $('#' + file.id),
$percent = $li.find('.progress span');
$percent.css('width', percentage * 100 + '%');
percentages[file.id][1] = percentage;
updateTotalProgress();
});
uploader.on('uploadSuccess', function (file, ret) {
var $file = $('#' + file.id);
try {
var responseText = (ret._raw || ret),
json = utils.str2json(responseText);
if (json.state == 'SUCCESS') {
_this.fileList.push(json);
$file.append('<span class="success"></span>');
// 触发上传附件事件
editor.fireEvent("uploadsuccess", {
res: json,
type: 'file'
});
} else {
$file.find('.error').text(json.state).show();
}
} catch (e) {
$file.find('.error').text(lang.errorServerUpload).show();
}
});
uploader.on('uploadError', function (file, code) {
});
uploader.on('error', function (code, file) {
if (code == 'Q_TYPE_DENIED' || code == 'F_EXCEED_SIZE') {
addFile(file);
}
});
uploader.on('uploadComplete', function (file, ret) {
});
$upload.on('click', function () {
if ($(this).hasClass('disabled')) {
return false;
}
if (state === 'ready') {
uploader.upload();
} else if (state === 'paused') {
uploader.upload();
} else if (state === 'uploading') {
uploader.stop();
}
});
$upload.addClass('state-' + state);
updateTotalProgress();
},
getQueueCount: function () {
var file, i, status, readyFile = 0, files = this.uploader.getFiles();
for (i = 0; file = files[i++];) {
status = file.getStatus();
if (status == 'queued' || status == 'uploading' || status == 'progress') readyFile++;
}
return readyFile;
},
getInsertList: function () {
var i, link, data, list = [],
prefix = editor.getOpt('fileUrlPrefix');
for (i = 0; i < this.fileList.length; i++) {
data = this.fileList[i];
link = data.url;
list.push({
title: data.original || link.substr(link.lastIndexOf('/') + 1),
url: prefix + link
});
}
return list;
}
};
/* 在线附件 */
function OnlineFile(target) {
this.container = utils.isString(target) ? document.getElementById(target) : target;
this.init();
}
OnlineFile.prototype = {
init: function () {
this.initContainer();
this.initEvents();
this.initData();
},
/* 初始化容器 */
initContainer: function () {
this.container.innerHTML = '';
this.list = document.createElement('ul');
this.clearFloat = document.createElement('li');
domUtils.addClass(this.list, 'list');
domUtils.addClass(this.clearFloat, 'clearFloat');
this.list.appendChild(this.clearFloat);
this.container.appendChild(this.list);
},
/* 初始化滚动事件,滚动到地步自动拉取数据 */
initEvents: function () {
var _this = this;
/* 滚动拉取图片 */
domUtils.on($G('fileList'), 'scroll', function (e) {
var panel = this;
if (panel.scrollHeight - (panel.offsetHeight + panel.scrollTop) < 10) {
_this.getFileData();
}
});
/* 选中图片 */
domUtils.on(this.list, 'click', function (e) {
var target = e.target || e.srcElement,
li = target.parentNode;
if (li.tagName.toLowerCase() == 'li') {
if (domUtils.hasClass(li, 'selected')) {
domUtils.removeClasses(li, 'selected');
} else {
domUtils.addClass(li, 'selected');
}
}
});
},
/* 初始化第一次的数据 */
initData: function () {
/* 拉取数据需要使用的值 */
this.state = 0;
this.listSize = editor.getOpt('fileManagerListSize');
this.listIndex = 0;
this.listEnd = false;
/* 第一次拉取数据 */
this.getFileData();
},
/* 向后台拉取图片列表数据 */
getFileData: function () {
var _this = this;
if (!_this.listEnd && !this.isLoadingData) {
this.isLoadingData = true;
ajax.request(editor.getActionUrl(editor.getOpt('fileManagerActionName')), {
timeout: 100000,
data: utils.extend({
start: this.listIndex,
size: this.listSize
}, editor.queryCommandValue('serverparam')),
headers: editor.options.serverHeaders || {},
method: 'get',
onsuccess: function (r) {
try {
var json = eval('(' + r.responseText + ')');
if (json.state == 'SUCCESS') {
_this.pushData(json.list);
_this.listIndex = parseInt(json.start) + parseInt(json.list.length);
if (_this.listIndex >= json.total) {
_this.listEnd = true;
}
_this.isLoadingData = false;
}
} catch (e) {
if (r.responseText.indexOf('ue_separate_ue') != -1) {
var list = r.responseText.split(r.responseText);
_this.pushData(list);
_this.listIndex = parseInt(list.length);
_this.listEnd = true;
_this.isLoadingData = false;
}
}
},
onerror: function () {
_this.isLoadingData = false;
}
});
}
},
/* 添加图片到列表界面上 */
pushData: function (list) {
var i, item, img, filetype, preview, icon, _this = this,
urlPrefix = editor.getOpt('fileManagerUrlPrefix');
for (i = 0; i < list.length; i++) {
if (list[i] && list[i].url) {
item = document.createElement('li');
icon = document.createElement('span');
filetype = list[i].url.substr(list[i].url.lastIndexOf('.') + 1);
if ("png|jpg|jpeg|gif|bmp".indexOf(filetype) != -1) {
preview = document.createElement('img');
domUtils.on(preview, 'load', (function (image) {
return function () {
_this.scale(image, image.parentNode.offsetWidth, image.parentNode.offsetHeight);
};
})(preview));
preview.width = 113;
preview.setAttribute('src', urlPrefix + list[i].url + (list[i].url.indexOf('?') == -1 ? '?noCache=' : '&noCache=') + (+new Date()).toString(36));
} else {
var ic = document.createElement('i'),
textSpan = document.createElement('span');
textSpan.innerHTML = list[i].original || list[i].url.substr(list[i].url.lastIndexOf('/') + 1);
preview = document.createElement('div');
preview.appendChild(ic);
preview.appendChild(textSpan);
domUtils.addClass(preview, 'file-wrapper');
domUtils.addClass(textSpan, 'file-title');
domUtils.addClass(ic, 'file-type-' + filetype);
domUtils.addClass(ic, 'file-preview');
}
domUtils.addClass(icon, 'icon');
item.setAttribute('data-url', urlPrefix + list[i].url);
if (list[i].original) {
item.setAttribute('data-title', list[i].original);
}
item.appendChild(preview);
item.appendChild(icon);
this.list.insertBefore(item, this.clearFloat);
}
}
},
/* 改变图片大小 */
scale: function (img, w, h, type) {
var ow = img.width,
oh = img.height;
if (type == 'justify') {
if (ow >= oh) {
img.width = w;
img.height = h * oh / ow;
img.style.marginLeft = '-' + parseInt((img.width - w) / 2) + 'px';
} else {
img.width = w * ow / oh;
img.height = h;
img.style.marginTop = '-' + parseInt((img.height - h) / 2) + 'px';
}
} else {
if (ow >= oh) {
img.width = w * ow / oh;
img.height = h;
img.style.marginLeft = '-' + parseInt((img.width - w) / 2) + 'px';
} else {
img.width = w;
img.height = h * oh / ow;
img.style.marginTop = '-' + parseInt((img.height - h) / 2) + 'px';
}
}
},
getInsertList: function () {
var i, lis = this.list.children, list = [];
for (i = 0; i < lis.length; i++) {
if (domUtils.hasClass(lis[i], 'selected')) {
var url = lis[i].getAttribute('data-url');
var title = lis[i].getAttribute('data-title') || url.substr(url.lastIndexOf('/') + 1);
list.push({
title: title,
url: url
});
}
}
return list;
}
};
})();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,818 +0,0 @@
@charset "utf-8";
.wrapper {
width: 570px;
_width: 575px;
margin: 10px auto;
zoom: 1;
position: relative
}
.tabbody {
height: 355px;
}
.tabbody .panel {
position: absolute;
width: 0;
height: 0;
background: #fff;
overflow: hidden;
display: none;
}
.tabbody .panel.focus {
width: 100%;
height: 355px;
display: block;
}
.tabbody .panel table td {
vertical-align: middle;
}
#audioUrl {
width: 380px;
height: 26px;
line-height: 26px;
margin: 8px 5px;
background: #FFF;
border: 1px solid #d7d7d7;
outline: none;
border-radius: 3px;
padding: 0 5px;
}
#audioSelect {
width: 100px;
display: inline-block;
background: #FFF;
border: 1px solid #EEE;
line-height: 26px;
text-align: center;
color: #333;
text-decoration: none;
border-radius: 3px;
vertical-align: middle;
}
#audioSearchTxt {
margin-left: 15px;
background: #FFF;
width: 200px;
height: 21px;
line-height: 21px;
border: 1px solid #d7d7d7;
}
#searchList {
width: 570px;
overflow: auto;
zoom: 1;
height: 270px;
}
#searchList div {
float: left;
width: 120px;
height: 135px;
margin: 5px 15px;
}
#searchList img {
margin: 2px 8px;
cursor: pointer;
border: 2px solid #fff
}
/*不用缩略图*/
#searchList p {
margin-left: 10px;
}
#audioType {
width: 65px;
height: 23px;
line-height: 22px;
border: 1px solid #d7d7d7;
}
#audioSearchBtn, #audioSearchReset {
/*width: 80px;*/
height: 25px;
line-height: 25px;
background: #eee;
border: 1px solid #d7d7d7;
cursor: pointer;
padding: 0 5px;
}
#preview {
position: relative;
width: 420px;
padding: 0;
overflow: hidden;
margin-left: 10px;
_margin-left: 5px;
height: 280px;
background-color: #ddd;
float: left
}
#preview .previewMsg {
position: absolute;
top: 0;
margin: 0;
padding: 0;
height: 280px;
width: 100%;
background-color: #666;
}
#preview .previewMsg span {
display: block;
margin: 125px auto 0 auto;
text-align: center;
font-size: 18px;
color: #fff;
}
#preview .previewaudio {
position: absolute;
top: 0;
margin: 0;
padding: 0;
height: 280px;
width: 100%;
}
.edui-audio-wrapper fieldset {
border: 1px solid #ddd;
padding-left: 5px;
margin-bottom: 20px;
padding-bottom: 5px;
width: 115px;
}
#audioInfo {
width: 120px;
float: left;
margin-left: 10px;
_margin-left: 7px;
}
fieldset {
border: 1px solid #ddd;
padding-left: 5px;
margin-bottom: 20px;
padding-bottom: 5px;
width: 115px;
}
fieldset legend {
font-weight: bold;
}
fieldset p {
line-height: 30px;
}
fieldset input.txt {
width: 65px;
height: 21px;
line-height: 21px;
margin: 8px 5px;
background: #FFF;
border: 1px solid #d7d7d7;
}
label.url {
font-weight: bold;
margin-left: 5px;
}
#audioFloat div {
cursor: pointer;
opacity: 0.5;
filter: alpha(opacity=50);
margin: 9px;
_margin: 5px;
width: 38px;
height: 36px;
float: left;
}
#audioFloat .focus {
opacity: 1;
filter: alpha(opacity=100)
}
span.view {
display: inline-block;
width: 30px;
float: right;
cursor: pointer;
color: blue
}
/* upload audio */
.tabbody #upload.panel {
width: 0;
height: 0;
overflow: hidden;
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
background: #fff;
display: block;
}
.tabbody #upload.panel.focus {
width: 100%;
height: 335px;
display: block;
clip: auto;
}
#upload_alignment div {
cursor: pointer;
opacity: 0.5;
filter: alpha(opacity=50);
margin: 9px;
_margin: 5px;
width: 38px;
height: 36px;
float: left;
}
#upload_alignment .focus {
opacity: 1;
filter: alpha(opacity=100)
}
#upload_left {
width: 427px;
float: left;
}
#upload_left .controller {
height: 30px;
clear: both;
}
#uploadaudioInfo {
margin-top: 10px;
float: right;
padding-right: 8px;
}
#upload .queueList {
margin: 0;
}
#upload p {
margin: 0;
}
.element-invisible {
width: 0 !important;
height: 0 !important;
border: 0;
padding: 0;
margin: 0;
overflow: hidden;
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
}
#upload .placeholder {
margin: 10px;
margin-right: 0;
border: 2px dashed #e6e6e6;
*border: 0px dashed #e6e6e6;
height: 161px;
padding-top: 150px;
text-align: center;
width: 97%;
float: left;
background: url(./images/image.png) center 70px no-repeat;
color: #cccccc;
font-size: 18px;
position: relative;
top: 0;
*margin-left: 0;
*left: 10px;
}
#upload .placeholder .webuploader-pick {
font-size: 18px;
background: #00b7ee;
border-radius: 3px;
line-height: 44px;
padding: 0 30px;
*width: 120px;
color: #fff;
display: inline-block;
margin: 0 auto 20px auto;
cursor: pointer;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
#upload .placeholder .webuploader-pick-hover {
background: #00a2d4;
}
#filePickerContainer {
text-align: center;
}
#upload .placeholder .flashTip {
color: #666666;
font-size: 12px;
position: absolute;
width: 100%;
text-align: center;
bottom: 20px;
}
#upload .placeholder .flashTip a {
color: #0785d1;
text-decoration: none;
}
#upload .placeholder .flashTip a:hover {
text-decoration: underline;
}
#upload .placeholder.webuploader-dnd-over {
border-color: #999999;
}
#upload .filelist {
list-style: none;
margin: 0;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
position: relative;
height: 285px;
}
#upload .filelist:after {
content: '';
display: block;
width: 0;
height: 0;
overflow: hidden;
clear: both;
}
#upload .filelist li {
width: 113px;
height: 113px;
background: url(./images/bg.png);
text-align: center;
margin: 15px 0 0 20px;
*margin: 15px 0 0 15px;
position: relative;
display: block;
float: left;
overflow: hidden;
font-size: 12px;
}
#upload .filelist li p.log {
position: relative;
top: -45px;
}
#upload .filelist li p.title {
position: absolute;
top: 0;
left: 0;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
top: 5px;
text-indent: 5px;
text-align: left;
}
#upload .filelist li p.progress {
position: absolute;
width: 100%;
bottom: 0;
left: 0;
height: 8px;
overflow: hidden;
z-index: 50;
margin: 0;
border-radius: 0;
background: none;
-webkit-box-shadow: 0 0 0;
}
#upload .filelist li p.progress span {
display: none;
overflow: hidden;
width: 0;
height: 100%;
background: #1483d8 url(./images/progress.png) repeat-x;
-webit-transition: width 200ms linear;
-moz-transition: width 200ms linear;
-o-transition: width 200ms linear;
-ms-transition: width 200ms linear;
transition: width 200ms linear;
-webkit-animation: progressmove 2s linear infinite;
-moz-animation: progressmove 2s linear infinite;
-o-animation: progressmove 2s linear infinite;
-ms-animation: progressmove 2s linear infinite;
animation: progressmove 2s linear infinite;
-webkit-transform: translateZ(0);
}
@-webkit-keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
@-moz-keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
@keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
#upload .filelist li p.imgWrap {
position: relative;
z-index: 2;
line-height: 113px;
vertical-align: middle;
overflow: hidden;
width: 113px;
height: 113px;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webit-transition: 200ms ease-out;
-moz-transition: 200ms ease-out;
-o-transition: 200ms ease-out;
-ms-transition: 200ms ease-out;
transition: 200ms ease-out;
}
#upload .filelist li p.imgWrap.notimage {
margin-top: 0;
width: 111px;
height: 111px;
border: 1px #eeeeee solid;
}
#upload .filelist li p.imgWrap.notimage i.file-preview {
margin-top: 15px;
}
#upload .filelist li img {
width: 100%;
}
#upload .filelist li p.error {
background: #f43838;
color: #fff;
position: absolute;
bottom: 0;
left: 0;
height: 28px;
line-height: 28px;
width: 100%;
z-index: 100;
display: none;
}
#upload .filelist li .success {
display: block;
position: absolute;
left: 0;
bottom: 0;
height: 40px;
width: 100%;
z-index: 200;
background: url(./images/success.png) no-repeat right bottom;
background-image: url(./images/success.gif) \9;
}
#upload .filelist li.filePickerBlock {
width: 113px;
height: 113px;
background: url(./images/image.png) no-repeat center 12px;
border: 1px solid #eeeeee;
border-radius: 0;
}
#upload .filelist li.filePickerBlock div.webuploader-pick {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
opacity: 0;
background: none;
font-size: 0;
}
#upload .filelist div.file-panel {
position: absolute;
height: 0;
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#80000000', endColorstr='#80000000') \0;
background: rgba(0, 0, 0, 0.5);
width: 100%;
top: 0;
left: 0;
overflow: hidden;
z-index: 300;
}
#upload .filelist div.file-panel span {
width: 24px;
height: 24px;
display: inline;
float: right;
text-indent: -9999px;
overflow: hidden;
background: url(./images/icons.png) no-repeat;
background: url(./images/icons.gif) no-repeat \9;
margin: 5px 1px 1px;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#upload .filelist div.file-panel span.rotateLeft {
display: none;
background-position: 0 -24px;
}
#upload .filelist div.file-panel span.rotateLeft:hover {
background-position: 0 0;
}
#upload .filelist div.file-panel span.rotateRight {
display: none;
background-position: -24px -24px;
}
#upload .filelist div.file-panel span.rotateRight:hover {
background-position: -24px 0;
}
#upload .filelist div.file-panel span.cancel {
background-position: -48px -24px;
}
#upload .filelist div.file-panel span.cancel:hover {
background-position: -48px 0;
}
#upload .statusBar {
height: 45px;
border-bottom: 1px solid #dadada;
margin: 0 10px;
padding: 0;
line-height: 45px;
vertical-align: middle;
position: relative;
}
#upload .statusBar .progress {
border: 1px solid #1483d8;
width: 198px;
background: #fff;
height: 18px;
position: absolute;
top: 12px;
display: none;
text-align: center;
line-height: 18px;
color: #6dbfff;
margin: 0 10px 0 0;
}
#upload .statusBar .progress span.percentage {
width: 0;
height: 100%;
left: 0;
top: 0;
background: #1483d8;
position: absolute;
}
#upload .statusBar .progress span.text {
position: relative;
z-index: 10;
}
#upload .statusBar .info {
display: inline-block;
font-size: 14px;
color: #666666;
}
#upload .statusBar .btns {
position: absolute;
top: 7px;
right: 0;
line-height: 30px;
}
#filePickerBtn {
display: inline-block;
float: left;
}
#upload .statusBar .btns .webuploader-pick,
#upload .statusBar .btns .uploadBtn,
#upload .statusBar .btns .uploadBtn.state-uploading,
#upload .statusBar .btns .uploadBtn.state-paused {
background: #ffffff;
border: 1px solid #cfcfcf;
color: #565656;
padding: 0 18px;
display: inline-block;
border-radius: 3px;
margin-left: 10px;
cursor: pointer;
font-size: 14px;
float: left;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#upload .statusBar .btns .webuploader-pick-hover,
#upload .statusBar .btns .uploadBtn:hover,
#upload .statusBar .btns .uploadBtn.state-uploading:hover,
#upload .statusBar .btns .uploadBtn.state-paused:hover {
background: #f0f0f0;
}
#upload .statusBar .btns .uploadBtn,
#upload .statusBar .btns .uploadBtn.state-paused {
background: #00b7ee;
color: #fff;
border-color: transparent;
}
#upload .statusBar .btns .uploadBtn:hover,
#upload .statusBar .btns .uploadBtn.state-paused:hover {
background: #00a2d4;
}
#upload .statusBar .btns .uploadBtn.disabled {
pointer-events: none;
filter: alpha(opacity=60);
-moz-opacity: 0.6;
-khtml-opacity: 0.6;
opacity: 0.6;
}
/* 在线文件的文件预览图标 */
i.file-preview {
display: block;
margin: 10px auto;
width: 70px;
height: 70px;
background-image: url("./images/file-icons.png");
background-image: url("./images/file-icons.gif") \9;
background-position: -140px center;
background-repeat: no-repeat;
}
i.file-preview.file-type-dir {
background-position: 0 center;
}
i.file-preview.file-type-file {
background-position: -140px center;
}
i.file-preview.file-type-filelist {
background-position: -210px center;
}
i.file-preview.file-type-zip,
i.file-preview.file-type-rar,
i.file-preview.file-type-7z,
i.file-preview.file-type-tar,
i.file-preview.file-type-gz,
i.file-preview.file-type-bz2 {
background-position: -280px center;
}
i.file-preview.file-type-xls,
i.file-preview.file-type-xlsx {
background-position: -350px center;
}
i.file-preview.file-type-doc,
i.file-preview.file-type-docx {
background-position: -420px center;
}
i.file-preview.file-type-ppt,
i.file-preview.file-type-pptx {
background-position: -490px center;
}
i.file-preview.file-type-vsd {
background-position: -560px center;
}
i.file-preview.file-type-pdf {
background-position: -630px center;
}
i.file-preview.file-type-txt,
i.file-preview.file-type-md,
i.file-preview.file-type-json,
i.file-preview.file-type-htm,
i.file-preview.file-type-xml,
i.file-preview.file-type-html,
i.file-preview.file-type-js,
i.file-preview.file-type-css,
i.file-preview.file-type-php,
i.file-preview.file-type-jsp,
i.file-preview.file-type-asp {
background-position: -700px center;
}
i.file-preview.file-type-apk {
background-position: -770px center;
}
i.file-preview.file-type-exe {
background-position: -840px center;
}
i.file-preview.file-type-ipa {
background-position: -910px center;
}
i.file-preview.file-type-mp4,
i.file-preview.file-type-swf,
i.file-preview.file-type-mkv,
i.file-preview.file-type-avi,
i.file-preview.file-type-flv,
i.file-preview.file-type-mov,
i.file-preview.file-type-mpg,
i.file-preview.file-type-mpeg,
i.file-preview.file-type-ogv,
i.file-preview.file-type-webm,
i.file-preview.file-type-rm,
i.file-preview.file-type-rmvb {
background-position: -980px center;
}
i.file-preview.file-type-ogg,
i.file-preview.file-type-wav,
i.file-preview.file-type-wmv,
i.file-preview.file-type-mid,
i.file-preview.file-type-mp3 {
background-position: -1050px center;
}
i.file-preview.file-type-jpg,
i.file-preview.file-type-jpeg,
i.file-preview.file-type-gif,
i.file-preview.file-type-bmp,
i.file-preview.file-type-png,
i.file-preview.file-type-psd {
background-position: -140px center;
}

View File

@@ -1,83 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<link rel="stylesheet" type="text/css" href="audio.css?c75591bc"/>
</head>
<body>
<div class="wrapper">
<div id="audioTab">
<div id="tabHeads" class="tabhead">
<span tabSrc="audio" class="focus" data-content-id="audio"><var id="lang_tab_insertV"></var></span>
<span tabSrc="upload" style="display:none;" data-content-id="upload"><var
id="lang_tab_uploadV"></var></span>
</div>
<div id="tabBodys" class="tabbody">
<div id="audio" class="panel focus">
<table>
<tr>
<td><label for="audioUrl" class="url"><var id="lang_audio_url"></var></label></td>
<td><input id="audioUrl" type="text"><a href="javascript:;" id="audioSelect"
style="display:none;">选择音频</a></td>
</tr>
</table>
<div style="padding:0 5px 5px 5px;color:#999;">
外链音频支持MP3格式
</div>
<div id="preview"></div>
<div id="audioInfo">
<fieldset>
<legend><var id="lang_alignment"></var></legend>
<div id="audioFloat"></div>
</fieldset>
</div>
</div>
<div id="upload" class="panel">
<div id="upload_left">
<div id="queueList" class="queueList">
<div class="statusBar element-invisible">
<div class="progress">
<span class="text">0%</span>
<span class="percentage"></span>
</div>
<div class="info"></div>
<div class="btns">
<div id="filePickerBtn"></div>
<div class="uploadBtn"><var id="lang_start_upload"></var></div>
</div>
</div>
<div id="dndArea" class="placeholder">
<div class="filePickerContainer">
<div id="filePickerReady"></div>
</div>
</div>
<ul class="filelist element-invisible">
<li id="filePickerBlock" class="filePickerBlock"></li>
</ul>
</div>
</div>
<div id="uploadaudioInfo">
<fieldset>
<legend><var id="lang_upload_alignment"></var></legend>
<div id="upload_alignment"></div>
</fieldset>
</div>
</div>
</div>
</div>
</div>
<!-- jquery -->
<script type="text/javascript" src="../../third-party/jquery-1.10.2.js?628072e7"></script>
<!-- webuploader -->
<script type="text/javascript" src="../../third-party/webuploader/webuploader.js?f37088cc"></script>
<link rel="stylesheet" type="text/css" href="../../third-party/webuploader/webuploader.css?0057c5c7">
<!-- audio -->
<script type="text/javascript" src="audio.js?9f84905f"></script>
</body>
</html>

View File

@@ -1,782 +0,0 @@
/**
* Created by JetBrains PhpStorm.
* User: taoqili
* Date: 12-2-20
* Time: 上午11:19
* To change this template use File | Settings | File Templates.
*/
(function () {
var audio = {},
uploadaudioList = [],
isModifyUploadaudio = false,
uploadFile;
var editorOpt = {};
window.onload = function () {
editorOpt = editor.getOpt('audioConfig');
$focus($G("audioUrl"));
initTabs();
initAudio();
initUpload();
};
/* 初始化tab标签 */
function initTabs() {
var tabs = $G('tabHeads').children;
for (var i = 0; i < tabs.length; i++) {
domUtils.on(tabs[i], "click", function (e) {
var j, bodyId, target = e.target || e.srcElement;
for (j = 0; j < tabs.length; j++) {
bodyId = tabs[j].getAttribute('data-content-id');
if (tabs[j] == target) {
domUtils.addClass(tabs[j], 'focus');
domUtils.addClass($G(bodyId), 'focus');
} else {
domUtils.removeClasses(tabs[j], 'focus');
domUtils.removeClasses($G(bodyId), 'focus');
}
}
});
}
if (!editorOpt.disableUpload) {
$G('tabHeads').querySelector('[data-content-id="upload"]').style.display = 'inline-block';
}
if (!!editorOpt.selectCallback) {
$G('audioSelect').style.display = 'inline-block';
domUtils.on($G('audioSelect'), "click", function (e) {
editorOpt.selectCallback(editor, function (info) {
if (info) {
$G('audioUrl').value = info.path;
createPreview(info.path);
}
});
});
}
}
function initAudio() {
createAlignButton(["audioFloat", "upload_alignment"]);
addUrlChangeListener($G("audioUrl"));
addOkListener();
//编辑视频时初始化相关信息
(function () {
var img = editor.selection.getRange().getClosedNode(), url;
if (img && img.className) {
var hasFakedClass = (img.className == "edui-faked-audio"),
hasUploadClass = img.className.indexOf("edui-upload-audio") != -1;
if (hasFakedClass || hasUploadClass) {
$G("audioUrl").value = url = img.getAttribute("_url");
var align = domUtils.getComputedStyle(img, "float"),
parentAlign = domUtils.getComputedStyle(img.parentNode, "text-align");
updateAlignButton(parentAlign === "center" ? "center" : align);
}
if (hasUploadClass) {
isModifyUploadaudio = true;
}
}
createPreview(url);
})();
}
/**
* 监听确认和取消两个按钮事件,用户执行插入或者清空正在播放的视频实例操作
*/
function addOkListener() {
dialog.onok = function () {
$G("preview").innerHTML = "";
var currentTab = findFocus("tabHeads", "tabSrc");
switch (currentTab) {
case "audio":
return insertSingle();
break;
// case "audioSearch":
// return insertSearch("searchList");
// break;
case "upload":
return insertUpload();
break;
}
};
dialog.oncancel = function () {
$G("preview").innerHTML = "";
};
}
/**
* 依据传入的align值更新按钮信息
* @param align
*/
function updateAlignButton(align) {
var aligns = $G("audioFloat").children;
for (var i = 0, ci; ci = aligns[i++];) {
if (ci.getAttribute("name") == align) {
if (ci.className != "focus") {
ci.className = "focus";
}
} else {
if (ci.className == "focus") {
ci.className = "";
}
}
}
}
/**
* 将单个视频信息插入编辑器中
*/
function insertSingle() {
var url = $G('audioUrl').value,
align = findFocus("audioFloat", "name");
if (!url) return false;
editor.execCommand('insertaudio', {
url: url,
}, isModifyUploadaudio ? 'upload' : null);
}
/**
* 将元素id下的所有代表视频的图片插入编辑器中
* @param id
*/
function insertSearch(id) {
var imgs = domUtils.getElementsByTagName($G(id), "img"),
audioObjs = [];
for (var i = 0, img; img = imgs[i++];) {
if (img.getAttribute("selected")) {
audioObjs.push({
url: img.getAttribute("ue_audio_url"),
width: 420,
height: 280,
align: "none"
});
}
}
editor.execCommand('insertaudio', audioObjs);
}
/**
* 找到id下具有focus类的节点并返回该节点下的某个属性
* @param id
* @param returnProperty
*/
function findFocus(id, returnProperty) {
var tabs = $G(id).children,
property;
for (var i = 0, ci; ci = tabs[i++];) {
if (ci.className == "focus") {
property = ci.getAttribute(returnProperty);
break;
}
}
return property;
}
/**
* 数字判断
* @param value
*/
function isNumber(value) {
return /(0|^[1-9]\d*$)/.test(value);
}
/**
* 创建图片浮动选择按钮
* @param ids
*/
function createAlignButton(ids) {
for (var i = 0, ci; ci = ids[i++];) {
var floatContainer = $G(ci),
nameMaps = {
"none": lang['default'],
"left": lang.floatLeft,
"right": lang.floatRight,
"center": lang.block
};
for (var j in nameMaps) {
var div = document.createElement("div");
div.setAttribute("name", j);
if (j == "none") div.className = "focus";
div.style.cssText = "background:url(images/" + j + "_focus.jpg);";
div.setAttribute("title", nameMaps[j]);
floatContainer.appendChild(div);
}
switchSelect(ci);
}
}
/**
* 选择切换
* @param selectParentId
*/
function switchSelect(selectParentId) {
var selects = $G(selectParentId).children;
for (var i = 0, ci; ci = selects[i++];) {
domUtils.on(ci, "click", function () {
for (var j = 0, cj; cj = selects[j++];) {
cj.className = "";
cj.removeAttribute && cj.removeAttribute("class");
}
this.className = "focus";
})
}
}
/**
* 监听url改变事件
* @param url
*/
function addUrlChangeListener(url) {
if (browser.ie) {
url.onpropertychange = function () {
createPreview(this.value);
}
} else {
url.addEventListener("input", function () {
createPreview(this.value);
}, false);
}
}
function createAudioHtml(url, param) {
param = param || {};
var str = [
"<audio",
(param.id ? ' id="' + param.id + '"' : ""),
(param.cls ? ' class="' + param.cls + '"' : ''),
' controls >',
'<source src="' + url + '" type="audio/mpeg' + '" />',
'</audio>',
];
return str.join('');
}
/**
* 根据url生成视频预览
* @param url
*/
function createPreview(url) {
if (!url) {
return;
}
$G("preview").innerHTML = '<div class="previewMsg"><span>' + lang.urlError + '</span></div>' +
'<div style="position: absolute; inset: 0; background: #FFF; text-align: center; display: flex; justify-items: center; align-items: center;">' +
'<div style="text-align:center;flex-grow:1;">' + createAudioHtml(url) + '</div>'
+ '</div>';
}
/* 插入上传视频 */
function insertUpload() {
var audioObjs = [],
uploadDir = editor.getOpt('audioUrlPrefix'),
align = findFocus("upload_alignment", "name") || 'none';
for (var key in uploadaudioList) {
var file = uploadaudioList[key];
audioObjs.push({
url: uploadDir + file.url,
align: align
});
}
var count = uploadFile.getQueueCount();
if (count) {
$('.info', '#queueList').html('<span style="color:red;">' + '还有2个未上传文件'.replace(/[\d]/, count) + '</span>');
return false;
} else {
editor.execCommand('insertaudio', audioObjs, 'upload');
}
}
/*初始化上传标签*/
function initUpload() {
uploadFile = new UploadFile('queueList');
}
/* 上传附件 */
function UploadFile(target) {
this.$wrap = target.constructor == String ? $('#' + target) : $(target);
this.init();
}
UploadFile.prototype = {
init: function () {
this.fileList = [];
this.initContainer();
this.initUploader();
},
initContainer: function () {
this.$queue = this.$wrap.find('.filelist');
},
/* 初始化容器 */
initUploader: function () {
var _this = this,
$ = jQuery, // just in case. Make sure it's not an other libaray.
$wrap = _this.$wrap,
// 图片容器
$queue = $wrap.find('.filelist'),
// 状态栏,包括进度和控制按钮
$statusBar = $wrap.find('.statusBar'),
// 文件总体选择信息。
$info = $statusBar.find('.info'),
// 上传按钮
$upload = $wrap.find('.uploadBtn'),
// 上传按钮
$filePickerBtn = $wrap.find('.filePickerBtn'),
// 上传按钮
$filePickerBlock = $wrap.find('.filePickerBlock'),
// 没选择文件之前的内容。
$placeHolder = $wrap.find('.placeholder'),
// 总体进度条
$progress = $statusBar.find('.progress').hide(),
// 添加的文件数量
fileCount = 0,
// 添加的文件总大小
fileSize = 0,
// 优化retina, 在retina下这个值是2
ratio = window.devicePixelRatio || 1,
// 缩略图大小
thumbnailWidth = 113 * ratio,
thumbnailHeight = 113 * ratio,
// 可能有pedding, ready, uploading, confirm, done.
state = '',
// 所有文件的进度信息key为file id
percentages = {},
supportTransition = (function () {
var s = document.createElement('p').style,
r = 'transition' in s ||
'WebkitTransition' in s ||
'MozTransition' in s ||
'msTransition' in s ||
'OTransition' in s;
s = null;
return r;
})(),
// WebUploader实例
uploader,
actionUrl = editor.getActionUrl(editor.getOpt('audioActionName')),
fileMaxSize = editor.getOpt('audioMaxSize'),
acceptExtensions = (editor.getOpt('audioAllowFiles') || []).join('').replace(/\./g, ',').replace(/^[,]/, '');
;
if (!WebUploader.Uploader.support()) {
$('#filePickerReady').after($('<div>').html(lang.errorNotSupport)).hide();
return;
} else if (!editor.getOpt('audioActionName')) {
$('#filePickerReady').after($('<div>').html(lang.errorLoadConfig)).hide();
return;
}
uploader = _this.uploader = WebUploader.create({
pick: {
id: '#filePickerReady',
label: lang.uploadSelectFile
},
swf: '../../third-party/webuploader/Uploader.swf',
server: actionUrl,
fileVal: editor.getOpt('audioFieldName'),
duplicate: true,
fileSingleSizeLimit: fileMaxSize,
headers: editor.getOpt('serverHeaders') || {},
compress: false
});
uploader.addButton({
id: '#filePickerBlock'
});
uploader.addButton({
id: '#filePickerBtn',
label: lang.uploadAddFile
});
setState('pedding');
// 当有文件添加进来时执行负责view的创建
function addFile(file) {
var $li = $('<li id="' + file.id + '">' +
'<p class="title">' + file.name + '</p>' +
'<p class="imgWrap"></p>' +
'<p class="progress"><span></span></p>' +
'</li>'),
$btns = $('<div class="file-panel">' +
'<span class="cancel">' + lang.uploadDelete + '</span>' +
'<span class="rotateRight">' + lang.uploadTurnRight + '</span>' +
'<span class="rotateLeft">' + lang.uploadTurnLeft + '</span></div>').appendTo($li),
$prgress = $li.find('p.progress span'),
$wrap = $li.find('p.imgWrap'),
$info = $('<p class="error"></p>').hide().appendTo($li),
showError = function (code) {
switch (code) {
case 'exceed_size':
text = lang.errorExceedSize;
break;
case 'interrupt':
text = lang.errorInterrupt;
break;
case 'http':
text = lang.errorHttp;
break;
case 'not_allow_type':
text = lang.errorFileType;
break;
default:
text = lang.errorUploadRetry;
break;
}
$info.text(text).show();
};
if (file.getStatus() === 'invalid') {
showError(file.statusText);
} else {
$wrap.text(lang.uploadPreview);
if ('|png|jpg|jpeg|bmp|gif|'.indexOf('|' + file.ext.toLowerCase() + '|') == -1) {
$wrap.empty().addClass('notimage').append('<i class="file-preview file-type-' + file.ext.toLowerCase() + '"></i>' +
'<span class="file-title">' + file.name + '</span>');
} else {
if (browser.ie && browser.version <= 7) {
$wrap.text(lang.uploadNoPreview);
} else {
uploader.makeThumb(file, function (error, src) {
if (error || !src || (/^data:/.test(src) && browser.ie && browser.version <= 7)) {
$wrap.text(lang.uploadNoPreview);
} else {
var $img = $('<img src="' + src + '">');
$wrap.empty().append($img);
$img.on('error', function () {
$wrap.text(lang.uploadNoPreview);
});
}
}, thumbnailWidth, thumbnailHeight);
}
}
percentages[file.id] = [file.size, 0];
file.rotation = 0;
/* 检查文件格式 */
if (!file.ext || acceptExtensions.indexOf(file.ext.toLowerCase()) == -1) {
showError('not_allow_type');
uploader.removeFile(file);
}
}
file.on('statuschange', function (cur, prev) {
if (prev === 'progress') {
$prgress.hide().width(0);
} else if (prev === 'queued') {
$li.off('mouseenter mouseleave');
$btns.remove();
}
// 成功
if (cur === 'error' || cur === 'invalid') {
showError(file.statusText);
percentages[file.id][1] = 1;
} else if (cur === 'interrupt') {
showError('interrupt');
} else if (cur === 'queued') {
percentages[file.id][1] = 0;
} else if (cur === 'progress') {
$info.hide();
$prgress.css('display', 'block');
} else if (cur === 'complete') {
}
$li.removeClass('state-' + prev).addClass('state-' + cur);
});
$li.on('mouseenter', function () {
$btns.stop().animate({height: 30});
});
$li.on('mouseleave', function () {
$btns.stop().animate({height: 0});
});
$btns.on('click', 'span', function () {
var index = $(this).index(),
deg;
switch (index) {
case 0:
uploader.removeFile(file);
return;
case 1:
file.rotation += 90;
break;
case 2:
file.rotation -= 90;
break;
}
if (supportTransition) {
deg = 'rotate(' + file.rotation + 'deg)';
$wrap.css({
'-webkit-transform': deg,
'-mos-transform': deg,
'-o-transform': deg,
'transform': deg
});
} else {
$wrap.css('filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation=' + (~~((file.rotation / 90) % 4 + 4) % 4) + ')');
}
});
$li.insertBefore($filePickerBlock);
}
// 负责view的销毁
function removeFile(file) {
var $li = $('#' + file.id);
delete percentages[file.id];
updateTotalProgress();
$li.off().find('.file-panel').off().end().remove();
}
function updateTotalProgress() {
var loaded = 0,
total = 0,
spans = $progress.children(),
percent;
$.each(percentages, function (k, v) {
total += v[0];
loaded += v[0] * v[1];
});
percent = total ? loaded / total : 0;
spans.eq(0).text(Math.round(percent * 100) + '%');
spans.eq(1).css('width', Math.round(percent * 100) + '%');
updateStatus();
}
function setState(val, files) {
if (val != state) {
var stats = uploader.getStats();
$upload.removeClass('state-' + state);
$upload.addClass('state-' + val);
switch (val) {
/* 未选择文件 */
case 'pedding':
$queue.addClass('element-invisible');
$statusBar.addClass('element-invisible');
$placeHolder.removeClass('element-invisible');
$progress.hide();
$info.hide();
uploader.refresh();
break;
/* 可以开始上传 */
case 'ready':
$placeHolder.addClass('element-invisible');
$queue.removeClass('element-invisible');
$statusBar.removeClass('element-invisible');
$progress.hide();
$info.show();
$upload.text(lang.uploadStart);
uploader.refresh();
break;
/* 上传中 */
case 'uploading':
$progress.show();
$info.hide();
$upload.text(lang.uploadPause);
break;
/* 暂停上传 */
case 'paused':
$progress.show();
$info.hide();
$upload.text(lang.uploadContinue);
break;
case 'confirm':
$progress.show();
$info.hide();
$upload.text(lang.uploadStart);
stats = uploader.getStats();
if (stats.successNum && !stats.uploadFailNum) {
setState('finish');
return;
}
break;
case 'finish':
$progress.hide();
$info.show();
if (stats.uploadFailNum) {
$upload.text(lang.uploadRetry);
} else {
$upload.text(lang.uploadStart);
}
break;
}
state = val;
updateStatus();
}
if (!_this.getQueueCount()) {
$upload.addClass('disabled')
} else {
$upload.removeClass('disabled')
}
}
function updateStatus() {
var text = '', stats;
if (state === 'ready') {
text = lang.updateStatusReady.replace('_', fileCount).replace('_KB', WebUploader.formatSize(fileSize));
} else if (state === 'confirm') {
stats = uploader.getStats();
if (stats.uploadFailNum) {
text = lang.updateStatusConfirm.replace('_', stats.successNum).replace('_', stats.successNum);
}
} else {
stats = uploader.getStats();
text = lang.updateStatusFinish.replace('_', fileCount).replace('_KB', WebUploader.formatSize(fileSize)).replace('_', stats.successNum);
if (stats.uploadFailNum) {
text += lang.updateStatusError.replace('_', stats.uploadFailNum);
}
}
$info.html(text);
}
uploader.on('fileQueued', function (file) {
fileCount++;
fileSize += file.size;
if (fileCount === 1) {
$placeHolder.addClass('element-invisible');
$statusBar.show();
}
addFile(file);
});
uploader.on('fileDequeued', function (file) {
fileCount--;
fileSize -= file.size;
removeFile(file);
updateTotalProgress();
});
uploader.on('filesQueued', function (file) {
if (!uploader.isInProgress() && (state == 'pedding' || state == 'finish' || state == 'confirm' || state == 'ready')) {
setState('ready');
}
updateTotalProgress();
});
uploader.on('all', function (type, files) {
switch (type) {
case 'uploadFinished':
setState('confirm', files);
break;
case 'startUpload':
/* 添加额外的GET参数 */
var params = utils.serializeParam(editor.queryCommandValue('serverparam')) || '',
url = utils.formatUrl(actionUrl + (actionUrl.indexOf('?') == -1 ? '?' : '&') + 'encode=utf-8&' + params);
uploader.option('server', url);
setState('uploading', files);
break;
case 'stopUpload':
setState('paused', files);
break;
}
});
uploader.on('uploadBeforeSend', function (file, data, header) {
//这里可以通过data对象添加POST参数
if (actionUrl.toLowerCase().indexOf('jsp') != -1) {
header['X_Requested_With'] = 'XMLHttpRequest';
}
});
uploader.on('uploadProgress', function (file, percentage) {
var $li = $('#' + file.id),
$percent = $li.find('.progress span');
$percent.css('width', percentage * 100 + '%');
percentages[file.id][1] = percentage;
updateTotalProgress();
});
uploader.on('uploadSuccess', function (file, ret) {
var $file = $('#' + file.id);
try {
var responseText = (ret._raw || ret),
json = utils.str2json(responseText);
if (json.state == 'SUCCESS') {
uploadaudioList.push({
'url': json.url,
'type': json.type,
'original': json.original
});
$file.append('<span class="success"></span>');
} else {
$file.find('.error').text(json.state).show();
}
} catch (e) {
$file.find('.error').text(lang.errorServerUpload).show();
}
});
uploader.on('uploadError', function (file, code) {
});
uploader.on('error', function (code, file) {
if (code == 'Q_TYPE_DENIED' || code == 'F_EXCEED_SIZE') {
addFile(file);
}
});
uploader.on('uploadComplete', function (file, ret) {
});
$upload.on('click', function () {
if ($(this).hasClass('disabled')) {
return false;
}
if (state === 'ready') {
uploader.upload();
} else if (state === 'paused') {
uploader.upload();
} else if (state === 'uploading') {
uploader.stop();
}
});
$upload.addClass('state-' + state);
updateTotalProgress();
},
getQueueCount: function () {
var file, i, status, readyFile = 0, files = this.uploader.getFiles();
for (i = 0; file = files[i++];) {
status = file.getStatus();
if (status == 'queued' || status == 'uploading' || status == 'progress') readyFile++;
}
return readyFile;
},
refresh: function () {
this.uploader.refresh();
}
};
})();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,193 +0,0 @@
.wrapper {
width: 424px;
margin: 10px auto;
zoom: 1;
position: relative
}
.tabbody {
height: 225px;
}
.tabbody .panel {
position: absolute;
width: 100%;
height: 100%;
background: #fff;
display: none;
}
.tabbody .focus {
display: block;
}
body {
font-size: 12px;
color: #888;
overflow: hidden;
}
input, label {
vertical-align: middle
}
.clear {
clear: both;
}
.pl {
padding-left: 18px;
padding-left: 23px \9;
}
#imageList {
width: 420px;
height: 215px;
margin-top: 10px;
overflow: hidden;
overflow-y: auto;
}
#imageList div {
float: left;
width: 100px;
height: 95px;
margin: 5px 10px;
}
#imageList img {
cursor: pointer;
border: 2px solid white;
}
.bgarea {
margin: 10px;
padding: 5px;
height: 84%;
border: 1px solid #A8A297;
}
.content div {
margin: 10px 0 10px 5px;
}
.content .iptradio {
margin: 0px 5px 5px 0px;
}
.txt {
width: 280px;
}
.wrapcolor {
height: 19px;
}
div.color {
float: left;
margin: 0;
}
#colorPicker {
width: 17px;
height: 17px;
border: 1px solid #CCC;
display: inline-block;
border-radius: 3px;
box-shadow: 2px 2px 5px #D3D6DA;
margin: 0;
float: left;
}
div.alignment, #custom {
margin-left: 23px;
margin-left: 28px \9;
}
#custom input {
height: 15px;
min-height: 15px;
width: 20px;
}
#repeatType {
width: 100px;
}
/* 图片管理样式 */
#imgManager {
width: 100%;
height: 225px;
}
#imgManager #imageList {
width: 100%;
overflow-x: hidden;
overflow-y: auto;
}
#imgManager ul {
display: block;
list-style: none;
margin: 0;
padding: 0;
}
#imgManager li {
float: left;
display: block;
list-style: none;
padding: 0;
width: 113px;
height: 113px;
margin: 9px 0 0 19px;
background-color: #eee;
overflow: hidden;
cursor: pointer;
position: relative;
}
#imgManager li.clearFloat {
float: none;
clear: both;
display: block;
width: 0;
height: 0;
margin: 0;
padding: 0;
}
#imgManager li img {
cursor: pointer;
}
#imgManager li .icon {
cursor: pointer;
width: 113px;
height: 113px;
position: absolute;
top: 0;
left: 0;
z-index: 2;
border: 0;
background-repeat: no-repeat;
}
#imgManager li .icon:hover {
width: 107px;
height: 107px;
border: 3px solid #1094fa;
}
#imgManager li.selected .icon {
background-image: url(images/success.png);
background-position: 75px 75px;
}
#imgManager li.selected .icon:hover {
width: 107px;
height: 107px;
border: 3px solid #1094fa;
background-position: 72px 72px;
}

View File

@@ -1,59 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<link rel="stylesheet" type="text/css" href="background.css?da860c7a">
</head>
<body>
<div id="bg_container" class="wrapper">
<div id="tabHeads" class="tabhead">
<span class="focus" data-content-id="normal"><var id="lang_background_normal"></var></span>
</div>
<div id="tabBodys" class="tabbody">
<div id="normal" class="panel focus">
<fieldset class="bgarea">
<legend><var id="lang_background_set"></var></legend>
<div class="content">
<div>
<label><input id="nocolorRadio" class="iptradio" type="radio" name="t" value="none"
checked="checked"><var id="lang_background_none"></var></label>
<label><input id="coloredRadio" class="iptradio" type="radio" name="t" value="color"><var
id="lang_background_colored"></var></label>
</div>
<div class="wrapcolor pl">
<div class="color">
<var id="lang_background_color"></var>:
</div>
<div id="colorPicker"></div>
<div class="clear"></div>
</div>
<div class="wrapcolor pl">
<label><var id="lang_background_netimg"></var>:</label><input class="txt" type="text" id="url">
</div>
<div id="alignment" class="alignment">
<var id="lang_background_align"></var>:<select id="repeatType">
<option value="center"></option>
<option value="repeat-x"></option>
<option value="repeat-y"></option>
<option value="repeat"></option>
<option value="self"></option>
</select>
</div>
<div id="custom">
<var id="lang_background_position"></var>:x:<input type="text" size="1" id="x" maxlength="4"
value="0">px&nbsp;&nbsp;y:<input type="text"
size="1"
id="y"
maxlength="4"
value="0">px
</div>
</div>
</fieldset>
</div>
</div>
</div>
<script type="text/javascript" src="background.js?dd36acd0"></script>
</body>
</html>

View File

@@ -1,370 +0,0 @@
(function () {
var onlineImage,
backupStyle = editor.queryCommandValue('background');
window.onload = function () {
initTabs();
initColorSelector();
};
/* 初始化tab标签 */
function initTabs() {
var tabs = $G('tabHeads').children;
for (var i = 0; i < tabs.length; i++) {
domUtils.on(tabs[i], "click", function (e) {
var target = e.target || e.srcElement;
for (var j = 0; j < tabs.length; j++) {
if (tabs[j] == target) {
tabs[j].className = "focus";
var contentId = tabs[j].getAttribute('data-content-id');
$G(contentId).style.display = "block";
} else {
tabs[j].className = "";
$G(tabs[j].getAttribute('data-content-id')).style.display = "none";
}
}
});
}
}
/* 初始化颜色设置 */
function initColorSelector() {
var obj = editor.queryCommandValue('background');
if (obj) {
var color = obj['background-color'],
repeat = obj['background-repeat'] || 'repeat',
image = obj['background-image'] || '',
position = obj['background-position'] || 'center center',
pos = position.split(' '),
x = parseInt(pos[0]) || 0,
y = parseInt(pos[1]) || 0;
if (repeat == 'no-repeat' && (x || y)) repeat = 'self';
image = image.match(/url[\s]*\(([^\)]*)\)/);
image = image ? image[1] : '';
updateFormState('colored', color, image, repeat, x, y);
} else {
updateFormState();
}
var updateHandler = function () {
updateFormState();
updateBackground();
}
domUtils.on($G('nocolorRadio'), 'click', updateBackground);
domUtils.on($G('coloredRadio'), 'click', updateHandler);
domUtils.on($G('url'), 'keyup', function () {
if ($G('url').value && $G('alignment').style.display == "none") {
utils.each($G('repeatType').children, function (item) {
item.selected = ('repeat' == item.getAttribute('value') ? 'selected' : false);
});
}
updateHandler();
});
domUtils.on($G('repeatType'), 'change', updateHandler);
domUtils.on($G('x'), 'keyup', updateBackground);
domUtils.on($G('y'), 'keyup', updateBackground);
initColorPicker();
}
/* 初始化颜色选择器 */
function initColorPicker() {
var me = editor,
cp = $G("colorPicker");
/* 生成颜色选择器ui对象 */
var popup = new UE.ui.Popup({
content: new UE.ui.ColorPicker({
noColorText: me.getLang("clearColor"),
editor: me,
onpickcolor: function (t, color) {
updateFormState('colored', color);
updateBackground();
UE.ui.Popup.postHide();
},
onpicknocolor: function (t, color) {
updateFormState('colored', 'transparent');
updateBackground();
UE.ui.Popup.postHide();
}
}),
editor: me,
onhide: function () {
}
});
/* 设置颜色选择器 */
domUtils.on(cp, "click", function () {
popup.showAnchor(this);
});
domUtils.on(document, 'mousedown', function (evt) {
var el = evt.target || evt.srcElement;
UE.ui.Popup.postHide(el);
});
domUtils.on(window, 'scroll', function () {
UE.ui.Popup.postHide();
});
}
/* 更新背景色设置面板 */
function updateFormState(radio, color, url, align, x, y) {
var nocolorRadio = $G('nocolorRadio'),
coloredRadio = $G('coloredRadio');
if (radio) {
nocolorRadio.checked = (radio == 'colored' ? false : 'checked');
coloredRadio.checked = (radio == 'colored' ? 'checked' : false);
}
if (color) {
domUtils.setStyle($G("colorPicker"), "background-color", color);
}
if (url && /^\//.test(url)) {
var a = document.createElement('a');
a.href = url;
browser.ie && (a.href = a.href);
url = browser.ie ? a.href : (a.protocol + '//' + a.host + a.pathname + a.search + a.hash);
}
if (url || url === '') {
$G('url').value = url;
}
if (align) {
utils.each($G('repeatType').children, function (item) {
item.selected = (align == item.getAttribute('value') ? 'selected' : false);
});
}
if (x || y) {
$G('x').value = parseInt(x) || 0;
$G('y').value = parseInt(y) || 0;
}
$G('alignment').style.display = coloredRadio.checked && $G('url').value ? '' : 'none';
$G('custom').style.display = coloredRadio.checked && $G('url').value && $G('repeatType').value == 'self' ? '' : 'none';
}
/* 更新背景颜色 */
function updateBackground() {
if ($G('coloredRadio').checked) {
var color = domUtils.getStyle($G("colorPicker"), "background-color"),
bgimg = $G("url").value,
align = $G("repeatType").value,
backgroundObj = {
"background-repeat": "no-repeat",
"background-position": "center center"
};
if (color) backgroundObj["background-color"] = color;
if (bgimg) backgroundObj["background-image"] = 'url(' + bgimg + ')';
if (align == 'self') {
backgroundObj["background-position"] = $G("x").value + "px " + $G("y").value + "px";
} else if (align == 'repeat-x' || align == 'repeat-y' || align == 'repeat') {
backgroundObj["background-repeat"] = align;
}
editor.execCommand('background', backgroundObj);
} else {
editor.execCommand('background', null);
}
}
/* 在线图片 */
function OnlineImage(target) {
this.container = utils.isString(target) ? document.getElementById(target) : target;
this.init();
}
OnlineImage.prototype = {
init: function () {
this.reset();
this.initEvents();
},
/* 初始化容器 */
initContainer: function () {
this.container.innerHTML = '';
this.list = document.createElement('ul');
this.clearFloat = document.createElement('li');
domUtils.addClass(this.list, 'list');
domUtils.addClass(this.clearFloat, 'clearFloat');
this.list.id = 'imageListUl';
this.list.appendChild(this.clearFloat);
this.container.appendChild(this.list);
},
/* 初始化滚动事件,滚动到地步自动拉取数据 */
initEvents: function () {
var _this = this;
/* 滚动拉取图片 */
domUtils.on($G('imageList'), 'scroll', function (e) {
var panel = this;
if (panel.scrollHeight - (panel.offsetHeight + panel.scrollTop) < 10) {
_this.getImageData();
}
});
/* 选中图片 */
domUtils.on(this.container, 'click', function (e) {
var target = e.target || e.srcElement,
li = target.parentNode,
nodes = $G('imageListUl').childNodes;
if (li.tagName.toLowerCase() == 'li') {
updateFormState('nocolor', null, '');
for (var i = 0, node; node = nodes[i++];) {
if (node == li && !domUtils.hasClass(node, 'selected')) {
domUtils.addClass(node, 'selected');
updateFormState('colored', null, li.firstChild.getAttribute("_src"), 'repeat');
} else {
domUtils.removeClasses(node, 'selected');
}
}
updateBackground();
}
});
},
/* 初始化第一次的数据 */
initData: function () {
/* 拉取数据需要使用的值 */
this.state = 0;
this.listSize = editor.getOpt('imageManagerListSize');
this.listIndex = 0;
this.listEnd = false;
/* 第一次拉取数据 */
this.getImageData();
},
/* 重置界面 */
reset: function () {
this.initContainer();
this.initData();
},
/* 向后台拉取图片列表数据 */
getImageData: function () {
var _this = this;
if (!_this.listEnd && !this.isLoadingData) {
this.isLoadingData = true;
var url = editor.getActionUrl(editor.getOpt('imageManagerActionName')),
isJsonp = utils.isCrossDomainUrl(url);
ajax.request(url, {
'timeout': 100000,
'dataType': isJsonp ? 'jsonp' : '',
'data': utils.extend({
start: this.listIndex,
size: this.listSize
}, editor.queryCommandValue('serverparam')),
'headers': editor.options.serverHeaders || {},
'method': 'get',
'onsuccess': function (r) {
try {
var json = isJsonp ? r : eval('(' + r.responseText + ')');
if (json.state == 'SUCCESS') {
_this.pushData(json.list);
_this.listIndex = parseInt(json.start) + parseInt(json.list.length);
if (_this.listIndex >= json.total) {
_this.listEnd = true;
}
_this.isLoadingData = false;
}
} catch (e) {
if (r.responseText.indexOf('ue_separate_ue') != -1) {
var list = r.responseText.split(r.responseText);
_this.pushData(list);
_this.listIndex = parseInt(list.length);
_this.listEnd = true;
_this.isLoadingData = false;
}
}
},
'onerror': function () {
_this.isLoadingData = false;
}
});
}
},
/* 添加图片到列表界面上 */
pushData: function (list) {
var i, item, img, icon, _this = this,
urlPrefix = editor.getOpt('imageManagerUrlPrefix');
for (i = 0; i < list.length; i++) {
if (list[i] && list[i].url) {
item = document.createElement('li');
img = document.createElement('img');
icon = document.createElement('span');
domUtils.on(img, 'load', (function (image) {
return function () {
_this.scale(image, image.parentNode.offsetWidth, image.parentNode.offsetHeight);
}
})(img));
img.width = 113;
img.setAttribute('src', urlPrefix + list[i].url + (list[i].url.indexOf('?') == -1 ? '?noCache=' : '&noCache=') + (+new Date()).toString(36));
img.setAttribute('_src', urlPrefix + list[i].url);
domUtils.addClass(icon, 'icon');
item.appendChild(img);
item.appendChild(icon);
this.list.insertBefore(item, this.clearFloat);
}
}
},
/* 改变图片大小 */
scale: function (img, w, h, type) {
var ow = img.width,
oh = img.height;
if (type == 'justify') {
if (ow >= oh) {
img.width = w;
img.height = h * oh / ow;
img.style.marginLeft = '-' + parseInt((img.width - w) / 2) + 'px';
} else {
img.width = w * ow / oh;
img.height = h;
img.style.marginTop = '-' + parseInt((img.height - h) / 2) + 'px';
}
} else {
if (ow >= oh) {
img.width = w * ow / oh;
img.height = h;
img.style.marginLeft = '-' + parseInt((img.width - w) / 2) + 'px';
} else {
img.width = w;
img.height = h * oh / ow;
img.style.marginTop = '-' + parseInt((img.height - h) / 2) + 'px';
}
}
},
getInsertList: function () {
var i, lis = this.list.children, list = [], align = getAlign();
for (i = 0; i < lis.length; i++) {
if (domUtils.hasClass(lis[i], 'selected')) {
var img = lis[i].firstChild,
src = img.getAttribute('_src');
list.push({
src: src,
_src: src,
floatStyle: align
});
}
}
return list;
}
};
dialog.onok = function () {
updateBackground();
editor.fireEvent('saveScene');
};
dialog.oncancel = function () {
editor.execCommand('background', backupStyle);
};
})();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,176 +0,0 @@
<!DOCTYPE html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<style type="text/css">
.wrapper {
width: 600px;
padding: 10px;
height: 352px;
overflow: hidden;
position: relative;
border-bottom: 1px solid #d7d7d7;
}
.wrapper .file-upload {
display: flex;
align-items: center;
}
.wrapper .file-upload .file-tip {
color: #999;
font-size: 12px;
padding-left: 10px;
flex-grow: 1;
}
.wrapper .file-manual {
background: #EEE;
padding: 10px;
border-radius: 5px;
margin-top: 10px;
line-height: 2;
}
.wrapper .file-manual .title {
font-weight: bold;
font-size: 120%;
}
.wrapper .file-manual .body {
}
.wrapper .file-manual .body li {
list-style: disc;
margin-left: 20px;
}
.wrapper .upload-button {
width: 100px;
height: 30px;
background-color: #F8F8F8;
border: 1px solid #EEE;
border-radius: 4px;
text-align: center;
line-height: 28px;
cursor: pointer;
position: relative;
flex-shrink: 0;
margin-right: 5px;
}
.wrapper .upload-button .text {
display: inline-block;
vertical-align: middle;
}
.wrapper .upload-button input {
position: absolute;
left: 0;
top: 0;
opacity: 0;
cursor: pointer;
height: 100%;
width: 100%;
}
.wrapper .file-result {
border: 1px solid #333;
padding: 10px;
border-radius: 5px;
position: absolute;
left: 10px;
right: 10px;
top: 50px;
background: #FFF;
bottom: 10px;
overflow: auto;
display: none;
}
.wrapper .file-input{
position: absolute;
left: 10px;
right: 10px;
top: 50px;
background: #EEE;
bottom: 10px;
border-radius: 5px;
display:none;
}
.wrapper .file-input textarea{
position: absolute;
left: 10px;
right: 10px;
bottom: 10px;
border: none;
resize: none;
border-radius: 5px;
padding: 5px;
outline: none;
top: 30px;
}
.wrapper .file-input .tool{
text-align: right;
padding: 5px 10px;
}
.wrapper .file-input .tool a{
display: inline-block;
text-decoration: none;
color: #333;
background: #FFF;
padding: 0 10px;
line-height: 20px;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="file-upload">
<div class="upload-button">
<div class="text">选择本地文件</div>
<input type="file" id="contentImport"/>
</div>
<div class="upload-button">
<div class="text" onclick="$('.file-input').show();">粘贴Markdown</div>
</div>
<div class="file-tip"></div>
</div>
<div class="file-manual">
<div class="title">
支持文档格式
</div>
<div class="body">
<ul>
<li><b>Word</b>docx</li>
<li><b>Markdown</b>md</li>
</ul>
</div>
</div>
<div class="file-result"></div>
<div class="file-input">
<textarea id="fileInputContent"></textarea>
<div class="tool">
<a href="javascript:;" id="fileInputConfirm">
确定
</a>
<a href="javascript:;" onclick="$(this).closest('.file-input').hide();">
关闭
</a>
</div>
</div>
</div>
<script src="../../third-party/jquery-1.10.2.js?628072e7"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/showdown/2.1.0/showdown.min.js"></script>
<script type="text/javascript" src="contentimport.js?5760833a"></script>
<script type="text/javascript">
utils.domReady(function () {
var options = {};
var callbacks = {};
contentImport.init(options, callbacks);
});
</script>
</body>
</html>

View File

@@ -1,91 +0,0 @@
var contentImport = {};
var g = $G;
contentImport.data = {
result: null,
};
contentImport.init = function (opt, callbacks) {
addUploadButtonListener();
addOkListener();
};
function processWord(file) {
$('.file-tip').html('正在转换Word文件请稍后...');
$('.file-result').html('').hide();
var reader = new FileReader();
reader.onload = function (loadEvent) {
mammoth.convertToHtml({
arrayBuffer: loadEvent.target.result
})
.then(function displayResult(result) {
$('.file-tip').html('转换成功');
contentImport.data.result = result.value;
$('.file-result').html(result.value).show();
}, function (error) {
$('.file-tip').html('Word文件转换失败:' + error);
});
};
reader.onerror = function (loadEvent) {
$('.file-tip').html('Word文件转换失败:' + loadEvent);
};
reader.readAsArrayBuffer(file);
}
function processMarkdown( markdown ){
var converter = new showdown.Converter();
var html = converter.makeHtml(markdown);
$('.file-tip').html('转换成功');
contentImport.data.result = html;
$('.file-result').html(html).show();
}
function processMarkdownFile(file) {
$('.file-tip').html('正在转换Markdown文件请稍后...');
$('.file-result').html('').hide();
var reader = new FileReader();
reader.onload = function (loadEvent) {
processMarkdown( loadEvent.target.result );
};
reader.onerror = function (loadEvent) {
$('.file-tip').html('Markdown文件转换失败:' + loadEvent);
};
reader.readAsText(file, "UTF-8");
}
function addUploadButtonListener() {
g('contentImport').addEventListener('change', function () {
const file = this.files[0];
const fileName = file.name;
const fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
switch (fileExt) {
case 'docx':
case 'doc':
processWord(file);
break;
case 'md':
processMarkdownFile(file);
break;
default:
$('.file-tip').html('不支持的文件格式:' + fileExt);
break;
}
});
g('fileInputConfirm').addEventListener('click', function () {
processMarkdown( g('fileInputContent').value );
$('.file-input').hide();
});
}
function addOkListener() {
dialog.onok = function () {
if (!contentImport.data.result) {
alert('请先上传文件识别内容');
return false;
}
editor.fireEvent('saveScene');
editor.execCommand("inserthtml", contentImport.data.result);
editor.fireEvent('saveScene');
};
dialog.oncancel = function () {
};
}

View File

@@ -1,129 +0,0 @@
.jd img {
background: transparent url(images/jxface2.gif?v=1.1) no-repeat scroll left top;
cursor: pointer;
width: 35px;
height: 35px;
display: block;
}
.pp img {
background: transparent url(images/fface.gif?v=1.1) no-repeat scroll left top;
cursor: pointer;
width: 25px;
height: 25px;
display: block;
}
.ldw img {
background: transparent url(images/wface.gif?v=1.1) no-repeat scroll left top;
cursor: pointer;
width: 35px;
height: 35px;
display: block;
}
.tsj img {
background: transparent url(images/tface.gif?v=1.1) no-repeat scroll left top;
cursor: pointer;
width: 35px;
height: 35px;
display: block;
}
.cat img {
background: transparent url(images/cface.gif?v=1.1) no-repeat scroll left top;
cursor: pointer;
width: 35px;
height: 35px;
display: block;
}
.bb img {
background: transparent url(images/bface.gif?v=1.1) no-repeat scroll left top;
cursor: pointer;
width: 35px;
height: 35px;
display: block;
}
.youa img {
background: transparent url(images/yface.gif?v=1.1) no-repeat scroll left top;
cursor: pointer;
width: 35px;
height: 35px;
display: block;
}
.smileytable td {
height: 37px;
}
#tabPanel {
margin-left: 5px;
overflow: hidden;
}
#tabContent {
float: left;
background: #FFFFFF;
}
#tabContent div {
display: none;
width: 480px;
overflow: hidden;
}
#tabIconReview.show {
left: 17px;
display: block;
}
.menuFocus {
background: #ACCD3C;
}
.menuDefault {
background: #FFFFFF;
}
#tabIconReview {
position: absolute;
left: 406px;
left: 398px \9;
top: 41px;
z-index: 65533;
width: 90px;
height: 76px;
}
img.review {
width: 90px;
height: 76px;
border: 2px solid #9cb945;
background: #FFFFFF;
background-position: center;
background-repeat: no-repeat;
}
.wrapper .tabbody {
position: relative;
float: left;
clear: both;
padding: 10px;
width: 95%;
}
.tabbody table {
width: 100%;
}
.tabbody td {
border: 1px solid #BAC498;
}
.tabbody td span {
display: block;
zoom: 1;
padding: 0 4px;
}

View File

@@ -1,70 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="robots" content="noindex, nofollow"/>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<link rel="stylesheet" type="text/css" href="emotion.css?d5b42328">
</head>
<body>
<div id="tabPanel" class="wrapper">
<div id="tabHeads" class="tabhead">
<span><var id="lang_input_choice"></var></span>
<span><var id="lang_input_Tuzki"></var></span>
<span><var id="lang_input_lvdouwa"></var></span>
<span><var id="lang_input_BOBO"></var></span>
<span><var id="lang_input_babyCat"></var></span>
<span><var id="lang_input_bubble"></var></span>
<span><var id="lang_input_youa"></var></span>
</div>
<div id="tabBodys" class="tabbody">
<div id="tab0"></div>
<div id="tab1"></div>
<div id="tab2"></div>
<div id="tab3"></div>
<div id="tab4"></div>
<div id="tab5"></div>
<div id="tab6"></div>
</div>
</div>
<div id="tabIconReview">
<img id='faceReview' class='review' src="../../themes/default/images/spacer.gif"/>
</div>
<script type="text/javascript" src="emotion.js?61027075"></script>
<script type="text/javascript">
var emotion = {
tabNum: 7, //切换面板数量
SmilmgName: {
tab0: ['j_00', 84],
tab1: ['t_00', 40],
tab2: ['w_00', 52],
tab3: ['B_00', 63],
tab4: ['C_00', 20],
tab5: ['i_f', 50],
tab6: ['y_00', 40]
}, //图片前缀名
imageFolders: {
tab0: 'jx2/',
tab1: 'tsj/',
tab2: 'ldw/',
tab3: 'bobo/',
tab4: 'babycat/',
tab5: 'face/',
tab6: 'youa/'
}, //图片对应文件夹路径
imageCss: {tab0: 'jd', tab1: 'tsj', tab2: 'ldw', tab3: 'bb', tab4: 'cat', tab5: 'pp', tab6: 'youa'}, //图片css类名
imageCssOffset: {tab0: 35, tab1: 35, tab2: 35, tab3: 35, tab4: 35, tab5: 25, tab6: 35}, //图片偏移
SmileyInfor: {
tab0: ['Kiss', 'Love', 'Yeah', '啊!', '背扭', '顶', '抖胸', '88', '汗', '瞌睡', '鲁拉', '拍砖', '揉脸', '生日快乐', '大笑', '瀑布汗~', '惊讶', '臭美', '傻笑', '抛媚眼', '发怒', '打酱油', '俯卧撑', '气愤', '?', '吻', '怒', '胜利', 'HI', 'KISS', '不说', '不要', '扯花', '大心', '顶', '大惊', '飞吻', '鬼脸', '害羞', '口水', '狂哭', '来', '发财了', '吃西瓜', '套牢', '害羞', '庆祝', '我来了', '敲打', '晕了', '胜利', '臭美', '被打了', '贪吃', '迎接', '酷', '微笑', '亲吻', '调皮', '惊恐', '耍酷', '发火', '害羞', '汗水', '大哭', '', '加油', '困', '你NB', '晕倒', '开心', '偷笑', '大哭', '滴汗', '叹气', '超赞', '??', '飞吻', '天使', '撒花', '生气', '被砸', '吓傻', '随意吐'],
tab1: ['Kiss', 'Love', 'Yeah', '啊!', '背扭', '顶', '抖胸', '88', '汗', '瞌睡', '鲁拉', '拍砖', '揉脸', '生日快乐', '摊手', '睡觉', '瘫坐', '无聊', '星星闪', '旋转', '也不行', '郁闷', '正Music', '抓墙', '撞墙至死', '歪头', '戳眼', '飘过', '互相拍砖', '砍死你', '扔桌子', '少林寺', '什么?', '转头', '我爱牛奶', '我踢', '摇晃', '晕厥', '在笼子里', '震荡'],
tab2: ['大笑', '瀑布汗~', '惊讶', '臭美', '傻笑', '抛媚眼', '发怒', '我错了', 'money', '气愤', '挑逗', '吻', '怒', '胜利', '委屈', '受伤', '说啥呢?', '闭嘴', '不', '逗你玩儿', '飞吻', '眩晕', '魔法', '我来了', '睡了', '我打', '闭嘴', '打', '打晕了', '刷牙', '爆揍', '炸弹', '倒立', '刮胡子', '邪恶的笑', '不要不要', '爱恋中', '放大仔细看', '偷窥', '超高兴', '晕', '松口气', '我跑', '享受', '修养', '哭', '汗', '啊~', '热烈欢迎', '打酱油', '俯卧撑', '?'],
tab3: ['HI', 'KISS', '不说', '不要', '扯花', '大心', '顶', '大惊', '飞吻', '鬼脸', '害羞', '口水', '狂哭', '来', '泪眼', '流泪', '生气', '吐舌', '喜欢', '旋转', '再见', '抓狂', '汗', '鄙视', '拜', '吐血', '嘘', '打人', '蹦跳', '变脸', '扯肉', '吃To', '吃花', '吹泡泡糖', '大变身', '飞天舞', '回眸', '可怜', '猛抽', '泡泡', '苹果', '亲', '', '骚舞', '烧香', '睡', '套娃娃', '捅捅', '舞倒', '西红柿', '爱慕', '摇', '摇摆', '杂耍', '招财', '被殴', '被球闷', '大惊', '理想', '欧打', '呕吐', '碎', '吐痰'],
tab4: ['发财了', '吃西瓜', '套牢', '害羞', '庆祝', '我来了', '敲打', '晕了', '胜利', '臭美', '被打了', '贪吃', '迎接', '酷', '顶', '幸运', '爱心', '躲', '送花', '选择'],
tab5: ['微笑', '亲吻', '调皮', '惊讶', '耍酷', '发火', '害羞', '汗水', '大哭', '得意', '鄙视', '困', '夸奖', '晕倒', '疑问', '媒婆', '狂吐', '青蛙', '发愁', '亲吻', '', '爱心', '心碎', '玫瑰', '礼物', '哭', '奸笑', '可爱', '得意', '呲牙', '暴汗', '楚楚可怜', '困', '哭', '生气', '惊讶', '口水', '彩虹', '夜空', '太阳', '钱钱', '灯泡', '咖啡', '蛋糕', '音乐', '爱', '胜利', '赞', '鄙视', 'OK'],
tab6: ['男兜', '女兜', '开心', '乖乖', '偷笑', '大笑', '抽泣', '大哭', '无奈', '滴汗', '叹气', '狂晕', '委屈', '超赞', '??', '疑问', '飞吻', '天使', '撒花', '生气', '被砸', '口水', '泪奔', '吓傻', '吐舌头', '点头', '随意吐', '旋转', '困困', '鄙视', '狂顶', '篮球', '再见', '欢迎光临', '恭喜发财', '稍等', '我在线', '恕不议价', '库房有货', '货在路上']
}
};
</script>
</body>
</html>

View File

@@ -1,186 +0,0 @@
window.onload = function () {
editor.setOpt({
emotionLocalization: false
});
emotion.SmileyPath = editor.options.emotionLocalization === true ? 'images/' : "http://img.baidu.com/hi/";
emotion.SmileyBox = createTabList(emotion.tabNum);
emotion.tabExist = createArr(emotion.tabNum);
initImgName();
initEvtHandler("tabHeads");
};
function initImgName() {
for (var pro in emotion.SmilmgName) {
var tempName = emotion.SmilmgName[pro],
tempBox = emotion.SmileyBox[pro],
tempStr = "";
if (tempBox.length) return;
for (var i = 1; i <= tempName[1]; i++) {
tempStr = tempName[0];
if (i < 10) tempStr = tempStr + '0';
tempStr = tempStr + i + '.gif';
tempBox.push(tempStr);
}
}
}
function initEvtHandler(conId) {
var tabHeads = $G(conId);
for (var i = 0, j = 0; i < tabHeads.childNodes.length; i++) {
var tabObj = tabHeads.childNodes[i];
if (tabObj.nodeType == 1) {
domUtils.on(tabObj, "click", (function (index) {
return function () {
switchTab(index);
};
})(j));
j++;
}
}
switchTab(0);
$G("tabIconReview").style.display = 'none';
}
function InsertSmiley(url, evt) {
var obj = {
src: editor.options.emotionLocalization ? editor.options.UEDITOR_HOME_URL + "dialogs/emotion/" + url : url
};
obj._src = obj.src;
editor.execCommand('insertimage', obj);
if (!evt.ctrlKey) {
dialog.popup.hide();
}
}
function switchTab(index) {
autoHeight(index);
if (emotion.tabExist[index] == 0) {
emotion.tabExist[index] = 1;
createTab('tab' + index);
}
//获取呈现元素句柄数组
var tabHeads = $G("tabHeads").getElementsByTagName("span"),
tabBodys = $G("tabBodys").getElementsByTagName("div"),
i = 0, L = tabHeads.length;
//隐藏所有呈现元素
for (; i < L; i++) {
tabHeads[i].className = "";
tabBodys[i].style.display = "none";
}
//显示对应呈现元素
tabHeads[index].className = "focus";
tabBodys[index].style.display = "block";
}
function autoHeight(index) {
var iframe = dialog.getDom("iframe"),
parent = iframe.parentNode.parentNode;
switch (index) {
case 0:
iframe.style.height = "380px";
parent.style.height = "392px";
break;
case 1:
iframe.style.height = "220px";
parent.style.height = "232px";
break;
case 2:
iframe.style.height = "260px";
parent.style.height = "272px";
break;
case 3:
iframe.style.height = "300px";
parent.style.height = "312px";
break;
case 4:
iframe.style.height = "140px";
parent.style.height = "152px";
break;
case 5:
iframe.style.height = "260px";
parent.style.height = "272px";
break;
case 6:
iframe.style.height = "230px";
parent.style.height = "242px";
break;
default:
}
}
function createTab(tabName) {
var faceVersion = "?v=1.1", //版本号
tab = $G(tabName), //获取将要生成的Div句柄
imagePath = emotion.SmileyPath + emotion.imageFolders[tabName], //获取显示表情和预览表情的路径
positionLine = 11 / 2, //中间数
iWidth = iHeight = 35, //图片长宽
iColWidth = 3, //表格剩余空间的显示比例
tableCss = emotion.imageCss[tabName],
cssOffset = emotion.imageCssOffset[tabName],
textHTML = ['<table class="smileytable">'],
i = 0, imgNum = emotion.SmileyBox[tabName].length, imgColNum = 11, faceImage,
sUrl, realUrl, posflag, offset, infor;
for (; i < imgNum;) {
textHTML.push('<tr>');
for (var j = 0; j < imgColNum; j++, i++) {
faceImage = emotion.SmileyBox[tabName][i];
if (faceImage) {
sUrl = imagePath + faceImage + faceVersion;
realUrl = imagePath + faceImage;
posflag = j < positionLine ? 0 : 1;
offset = cssOffset * i * (-1) - 1;
infor = emotion.SmileyInfor[tabName][i];
textHTML.push('<td class="' + tableCss + '" border="1" width="' + iColWidth + '%" style="border-collapse:collapse;" align="center" bgcolor="transparent" onclick="InsertSmiley(\'' + realUrl.replace(/'/g, "\\'") + '\',event)" onmouseover="over(this,\'' + sUrl + '\',\'' + posflag + '\')" onmouseout="out(this)">');
textHTML.push('<span>');
textHTML.push('<img style="background-position:left ' + offset + 'px;" title="' + infor + '" src="' + emotion.SmileyPath + (editor.options.emotionLocalization ? '0.gif" width="' : 'default/0.gif" width="') + iWidth + '" height="' + iHeight + '"></img>');
textHTML.push('</span>');
} else {
textHTML.push('<td width="' + iColWidth + '%" bgcolor="#FFFFFF">');
}
textHTML.push('</td>');
}
textHTML.push('</tr>');
}
textHTML.push('</table>');
textHTML = textHTML.join("");
tab.innerHTML = textHTML;
}
function over(td, srcPath, posFlag) {
td.style.backgroundColor = "#ACCD3C";
$G('faceReview').style.backgroundImage = "url(" + srcPath + ")";
if (posFlag == 1) $G("tabIconReview").className = "show";
$G("tabIconReview").style.display = 'block';
}
function out(td) {
td.style.backgroundColor = "transparent";
var tabIconRevew = $G("tabIconReview");
tabIconRevew.className = "";
tabIconRevew.style.display = 'none';
}
function createTabList(tabNum) {
var obj = {};
for (var i = 0; i < tabNum; i++) {
obj["tab" + i] = [];
}
return obj;
}
function createArr(tabNum) {
var arr = [];
for (var i = 0; i < tabNum; i++) {
arr[i] = 0;
}
return arr;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -1,98 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<style type="text/css">
.wrapper {
box-sizing: border-box;
width: 800px;
height: 390px;
overflow: hidden;
position: relative;
border-bottom: 1px solid #d7d7d7
}
.editor-wrap {
display: flex;
margin: 10px;
}
.editor-wrap #editor {
width: 0;
flex-grow: 1;
border: 1px solid #CCC;
border-radius: 3px;
padding: 5px;
height: 100px;
outline: none;
}
.input-tip {
margin: 10px;
}
.input-tip a {
color: #0f0d0d;
}
.editor-preview {
background: #FFF;
border-radius: 3px;
border: 1px solid #EEE;
display: none;
margin: 10px;
}
.editor-preview .title {
padding: 5px;
}
.editor-preview .body {
padding: 5px 5px 15px 5px;
text-align: center;
}
.editor-preview .body .image {
max-width: 100%;
max-height: 100px;
}
</style>
</head>
<body>
<div class="wrapper">
<div id="modeLive" style="display:none;">
<iframe id="liveEditor"
frameborder="0"
style="width:800px;height:390px;border: 0;outline: none;"
></iframe>
</div>
<div id="modePlain" style="display:none;">
<div class="editor-wrap">
<textarea id="editor"></textarea>
</div>
<div class="input-tip">
基于 latex 语法,<a href="javascript:;" id="inputDemo">点击输入示例</a>
</div>
<div class="editor-preview" id="preview">
<div class="title">预览</div>
<div class="body">
<img class="image" id="previewImage"/>
</div>
</div>
</div>
</div>
<script src="../../third-party/jquery-1.10.2.js?628072e7"></script>
<script type="text/javascript" src="../../third-party/clipboard/clipboard.js?555edf0a"></script>
<script type="text/javascript" src="formula.js?8fdd0a42"></script>
<script type="text/javascript">
utils.domReady(function () {
Formula.init();
});
</script>
</body>
</html>

View File

@@ -1,147 +0,0 @@
function preg_quote(str, delimiter) {
// Quote regular expression characters plus an optional character
//
// version: 1107.2516
// discuss at: http://phpjs.org/functions/preg_quote
// + original by: booeyOH
// + improved by: Ates Goral (http://magnetiq.com)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + bugfixed by: Onno Marsman
// + improved by: Brett Zamir (http://brett-zamir.me)
// * example 1: preg_quote("$40");
// * returns 1: '\$40'
// * example 2: preg_quote("*RRRING* Hello?");
// * returns 2: '\*RRRING\* Hello\?'
// * example 3: preg_quote("\\.+*?[^]$(){}=!<>|:");
// * returns 3: '\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:'
return (str + '').replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + (delimiter || '') + '-]', 'g'), '\\$&');
}
function loadScript(url, cb) {
var script;
script = document.createElement('script');
script.src = url;
script.onload = function () {
cb && cb({isNew: true})
};
document.getElementsByTagName('head')[0].appendChild(script);
}
var Formula = {
mode: 'plain',
latexeasy: null,
init: function () {
// console.log('Formula.init')
Formula.initMode();
Formula.initEvent();
Formula.initSubmit();
},
renderPlain: function () {
var $preview = $('#preview');
var value = $('#editor').val();
if (!value) {
$preview.hide();
return;
}
value = encodeURIComponent(value);
var formulaConfig = editor.getOpt('formulaConfig');
var src = formulaConfig.imageUrlTemplate.replace(/\{\}/, value);
$('#previewImage').attr('src', src);
$preview.show();
},
setValuePlain: function (value) {
$('#editor').val(value);
Formula.renderPlain();
},
setValueLive: function (value) {
if (!Formula.latexeasy) {
setTimeout(function () {
Formula.setValueLive(value);
}, 100);
return;
}
Formula.latexeasy.call('set.latex', {latex: value});
},
initMode: function () {
var formulaConfig = editor.getOpt('formulaConfig');
if ('live' === formulaConfig.editorMode) {
$('#liveEditor').attr('src', formulaConfig.editorLiveServer + '/editor');
$('#modeLive').show();
Formula.mode = 'live';
} else {
$('#modePlain').show();
Formula.mode = 'plain';
}
var img = editor.selection.getRange().getClosedNode();
if (img && img.getAttribute('data-formula-image') !== null) {
var value = img.getAttribute('data-formula-image');
if (value) {
Formula.setValue(decodeURIComponent(value));
}
}
},
setValue: function (value) {
switch (Formula.mode) {
case 'plain':
Formula.setValuePlain(value);
break;
case 'live':
Formula.setValueLive(value);
break;
}
},
getValue: function (cb) {
switch (Formula.mode) {
case 'plain':
cb($.trim($('#editor').val()));
break;
case 'live':
Formula.latexeasy.call('get.latex', {}, function (data) {
cb(data.latex);
});
break;
}
},
initEvent: function () {
var changeTimer = null, le;
switch (Formula.mode) {
case 'plain':
// console.log('Formula.initEvent');
$('#editor').on('change keypress', function () {
changeTimer && clearTimeout(changeTimer);
changeTimer = setTimeout(function () {
Formula.renderPlain();
}, 1000);
});
$('#inputDemo').on('click', function () {
$('#editor').val('f(a) = \\frac{1}{2\\pi i} \\oint\\frac{f(z)}{z-a}dz');
Formula.renderPlain();
});
break;
case 'live':
var formulaConfig = editor.getOpt('formulaConfig');
loadScript(formulaConfig.editorLiveServer + '/vendor/LatexEasyEditor/editor/sdk.js', function () {
le = new window.LatexEasy(document.getElementById('liveEditor'));
le.on('ready', function () {
Formula.latexeasy = le;
});
le.init();
});
break;
}
},
initSubmit: function () {
dialog.onclose = function (t, ok) {
if (!ok) {
return true;
}
// console.log('onclose', t, ok);
Formula.getValue(function (value) {
editor.execCommand('formula', value);
editor.fireEvent('saveScene');
dialog.close(false);
});
return false;
};
}
};

View File

@@ -1,37 +0,0 @@
.wrapper {
width: 370px;
margin: 10px auto;
zoom: 1;
}
.tabbody {
height: 360px;
}
.tabbody .panel {
width: 100%;
height: 360px;
position: absolute;
background: #fff;
}
.tabbody .panel h1 {
font-size: 26px;
margin: 5px 0 0 5px;
}
.tabbody .panel p {
font-size: 12px;
margin: 5px 0 0 5px;
}
.tabbody table {
width: 90%;
line-height: 20px;
margin: 5px 0 0 5px;;
}
.tabbody table thead {
font-weight: bold;
line-height: 25px;
}

View File

@@ -1,82 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>帮助</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<link rel="stylesheet" type="text/css" href="help.css?81231bdb">
</head>
<body>
<div class="wrapper" id="helptab">
<div id="tabHeads" class="tabhead">
<span class="focus" tabsrc="about"><var id="lang_input_about"></var></span>
<span tabsrc="shortcuts"><var id="lang_input_shortcuts"></var></span>
</div>
<div id="tabBodys" class="tabbody">
<div id="about" class="panel">
<h1>UEditor Plus</h1>
<p id="version"></p>
<p><var id="lang_input_introduction"></var></p>
</div>
<div id="shortcuts" class="panel">
<table>
<thead>
<tr>
<td><var id="lang_Txt_shortcuts"></var></td>
<td><var id="lang_Txt_func"></var></td>
</tr>
</thead>
<tbody>
<tr>
<td>ctrl+b</td>
<td><var id="lang_Txt_bold"></var></td>
</tr>
<tr>
<td>ctrl+c</td>
<td><var id="lang_Txt_copy"></var></td>
</tr>
<tr>
<td>ctrl+x</td>
<td><var id="lang_Txt_cut"></var></td>
</tr>
<tr>
<td>ctrl+v</td>
<td><var id="lang_Txt_Paste"></var></td>
</tr>
<tr>
<td>ctrl+y</td>
<td><var id="lang_Txt_undo"></var></td>
</tr>
<tr>
<td>ctrl+z</td>
<td><var id="lang_Txt_redo"></var></td>
</tr>
<tr>
<td>ctrl+i</td>
<td><var id="lang_Txt_italic"></var></td>
</tr>
<tr>
<td>ctrl+u</td>
<td><var id="lang_Txt_underline"></var></td>
</tr>
<tr>
<td>ctrl+a</td>
<td><var id="lang_Txt_selectAll"></var></td>
</tr>
<tr>
<td>shift+enter</td>
<td><var id="lang_Txt_visualEnter"></var></td>
</tr>
<tr>
<td>alt+z</td>
<td><var id="lang_Txt_fullscreen"></var></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script type="text/javascript" src="help.js?0a6823d2"></script>
</body>
</html>

View File

@@ -1,57 +0,0 @@
/**
* Created with JetBrains PhpStorm.
* User: xuheng
* Date: 12-9-26
* Time: 下午1:06
* To change this template use File | Settings | File Templates.
*/
/**
* tab点击处理事件
* @param tabHeads
* @param tabBodys
* @param obj
*/
function clickHandler(tabHeads, tabBodys, obj) {
//head样式更改
for (var k = 0, len = tabHeads.length; k < len; k++) {
tabHeads[k].className = "";
}
obj.className = "focus";
//body显隐
var tabSrc = obj.getAttribute("tabSrc");
for (var j = 0, length = tabBodys.length; j < length; j++) {
var body = tabBodys[j],
id = body.getAttribute("id");
body.onclick = function () {
this.style.zoom = 1;
};
if (id != tabSrc) {
body.style.zIndex = 1;
} else {
body.style.zIndex = 200;
}
}
}
/**
* TAB切换
* @param tabParentId tab的父节点ID或者对象本身
*/
function switchTab(tabParentId) {
var tabElements = $G(tabParentId).children,
tabHeads = tabElements[0].children,
tabBodys = tabElements[1].children;
for (var i = 0, length = tabHeads.length; i < length; i++) {
var head = tabHeads[i];
if (head.className === "focus") clickHandler(tabHeads, tabBodys, head);
head.onclick = function () {
clickHandler(tabHeads, tabBodys, this);
}
}
}
switchTab("helptab");
document.getElementById('version').innerHTML = parent.UE.version;

View File

@@ -1,752 +0,0 @@
@charset "utf-8";
/* dialog样式 */
.wrapper {
zoom: 1;
width: 630px;
*width: 626px;
height: 380px;
margin: 0 auto;
padding: 10px;
position: relative;
font-family: sans-serif;
}
/*tab样式框大小*/
.tabhead {
float: left;
}
.tabbody {
width: 100%;
height: 346px;
position: relative;
clear: both;
}
.tabbody .panel {
position: absolute;
width: 0;
height: 0;
background: #fff;
overflow: hidden;
display: none;
}
.tabbody .panel.focus {
width: 100%;
height: 346px;
display: block;
}
/* 图片对齐方式 */
.alignBar {
float: right;
margin-top: 5px;
position: relative;
}
.alignBar .algnLabel {
float: left;
height: 20px;
line-height: 20px;
}
.alignBar #alignIcon {
zoom: 1;
_display: inline;
display: inline-block;
position: relative;
}
.alignBar #alignIcon span {
float: left;
cursor: pointer;
display: block;
width: 19px;
height: 17px;
margin-right: 3px;
margin-left: 3px;
background-image: url(./images/alignicon.jpg);
}
.alignBar #alignIcon .none-align {
background-position: 0 -18px;
}
.alignBar #alignIcon .left-align {
background-position: -20px -18px;
}
.alignBar #alignIcon .right-align {
background-position: -40px -18px;
}
.alignBar #alignIcon .center-align {
background-position: -60px -18px;
}
.alignBar #alignIcon .none-align.focus {
background-position: 0 0;
}
.alignBar #alignIcon .left-align.focus {
background-position: -20px 0;
}
.alignBar #alignIcon .right-align.focus {
background-position: -40px 0;
}
.alignBar #alignIcon .center-align.focus {
background-position: -60px 0;
}
/* 远程图片样式 */
#remote {
z-index: 200;
}
#remote .top {
width: 100%;
margin-top: 25px;
}
#remote .left {
display: block;
float: left;
width: 300px;
height: 10px;
}
#remote .right {
display: block;
float: right;
width: 300px;
height: 10px;
}
#remote .row {
margin-left: 20px;
clear: both;
height: 40px;
}
#remote .row label {
text-align: center;
width: 50px;
zoom: 1;
_display: inline;
display: inline-block;
vertical-align: middle;
}
#remote .row label.algnLabel {
float: left;
}
#remote input.text {
width: 150px;
padding: 3px 6px;
font-size: 14px;
line-height: 1.42857143;
color: #555;
background-color: #fff;
background-image: none;
border: 1px solid #ccc;
border-radius: 4px;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
-webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
#remote input.text:focus {
outline: 0;
}
#remote #url {
width: 400px;
margin-bottom: 2px;
}
#remote #imageSelect {
width: 100px;
display: inline-block;
background: #FFF;
border: 1px solid #EEE;
line-height: 26px;
text-align: center;
color: #333;
text-decoration: none;
border-radius: 3px;
vertical-align: top;
}
#remote #width,
#remote #height {
width: 30px;
margin-left: 2px;
margin-right: 2px;
text-align: center;
}
#remote #border,
#remote #vhSpace,
#remote #title {
width: 180px;
margin-right: 5px;
}
#remote #lock {
display: inline-block;
vertical-align: middle;
}
#remote #lockicon {
zoom: 1;
_display: inline;
display: inline-block;
width: 20px;
height: 20px;
background: url("../../themes/default/images/lock.gif") -13px -13px no-repeat;
vertical-align: middle;
}
#remote #preview {
clear: both;
width: 260px;
height: 240px;
z-index: 9999;
margin-top: 10px;
background-color: #eee;
overflow: hidden;
}
/* 上传图片 */
.tabbody #upload.panel {
width: 0;
height: 0;
overflow: hidden;
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
background: #fff;
display: block;
}
.tabbody #upload.panel.focus {
width: 100%;
height: 346px;
display: block;
clip: auto;
}
#upload .queueList {
margin: 0;
width: 100%;
height: 100%;
position: absolute;
overflow: hidden;
}
#upload p {
margin: 0;
}
.element-invisible {
width: 0 !important;
height: 0 !important;
border: 0;
padding: 0;
margin: 0;
overflow: hidden;
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
}
#upload .placeholder {
margin: 10px;
border: 2px dashed #e6e6e6;
*border: 0px dashed #e6e6e6;
height: 172px;
padding-top: 150px;
text-align: center;
background: url(./images/image.png) center 70px no-repeat;
color: #cccccc;
font-size: 18px;
position: relative;
top: 0;
*top: 10px;
}
#upload .placeholder .webuploader-pick {
font-size: 18px;
background: #00b7ee;
border-radius: 3px;
line-height: 44px;
padding: 0 30px;
*width: 120px;
color: #fff;
display: inline-block;
margin: 0 auto 20px auto;
cursor: pointer;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
}
#upload .placeholder .webuploader-pick-hover {
background: #00a2d4;
}
#filePickerContainer {
text-align: center;
}
#upload .placeholder .flashTip {
color: #666666;
font-size: 12px;
position: absolute;
width: 100%;
text-align: center;
bottom: 20px;
}
#upload .placeholder .flashTip a {
color: #0785d1;
text-decoration: none;
}
#upload .placeholder .flashTip a:hover {
text-decoration: underline;
}
#upload .placeholder.webuploader-dnd-over {
border-color: #999999;
}
#upload .filelist {
list-style: none;
margin: 0;
padding: 0;
overflow-x: hidden;
overflow-y: auto;
position: relative;
height: 300px;
}
#upload .filelist:after {
content: '';
display: block;
width: 0;
height: 0;
overflow: hidden;
clear: both;
position: relative;
}
#upload .filelist li {
width: 113px;
height: 113px;
background: url(./images/bg.png);
text-align: center;
margin: 9px 0 0 9px;
*margin: 6px 0 0 6px;
position: relative;
display: block;
float: left;
overflow: hidden;
font-size: 12px;
}
#upload .filelist li p.log {
position: relative;
top: -45px;
}
#upload .filelist li p.title {
position: absolute;
top: 0;
left: 0;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
top: 5px;
text-indent: 5px;
text-align: left;
}
#upload .filelist li p.progress {
position: absolute;
width: 100%;
bottom: 0;
left: 0;
height: 8px;
overflow: hidden;
z-index: 50;
margin: 0;
border-radius: 0;
background: none;
-webkit-box-shadow: 0 0 0;
}
#upload .filelist li p.progress span {
display: none;
overflow: hidden;
width: 0;
height: 100%;
background: #1483d8 url(./images/progress.png) repeat-x;
-webit-transition: width 200ms linear;
-moz-transition: width 200ms linear;
-o-transition: width 200ms linear;
-ms-transition: width 200ms linear;
transition: width 200ms linear;
-webkit-animation: progressmove 2s linear infinite;
-moz-animation: progressmove 2s linear infinite;
-o-animation: progressmove 2s linear infinite;
-ms-animation: progressmove 2s linear infinite;
animation: progressmove 2s linear infinite;
-webkit-transform: translateZ(0);
}
@-webkit-keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
@-moz-keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
@keyframes progressmove {
0% {
background-position: 0 0;
}
100% {
background-position: 17px 0;
}
}
#upload .filelist li p.imgWrap {
position: relative;
z-index: 2;
line-height: 113px;
vertical-align: middle;
overflow: hidden;
width: 113px;
height: 113px;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
-webit-transition: 200ms ease-out;
-moz-transition: 200ms ease-out;
-o-transition: 200ms ease-out;
-ms-transition: 200ms ease-out;
transition: 200ms ease-out;
}
#upload .filelist li img {
width: 100%;
}
#upload .filelist li p.error {
background: #f43838;
color: #fff;
position: absolute;
bottom: 0;
left: 0;
height: 28px;
line-height: 28px;
width: 100%;
z-index: 100;
display: none;
}
#upload .filelist li .success {
display: block;
position: absolute;
left: 0;
bottom: 0;
height: 40px;
width: 100%;
z-index: 200;
background: url(./images/success.png) no-repeat right bottom;
background: url(./images/success.gif) no-repeat right bottom \9;
}
#upload .filelist li.filePickerBlock {
width: 113px;
height: 113px;
background: url(./images/image.png) no-repeat center 12px;
border: 1px solid #eeeeee;
border-radius: 0;
}
#upload .filelist li.filePickerBlock div.webuploader-pick {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
opacity: 0;
background: none;
font-size: 0;
}
#upload .filelist div.file-panel {
position: absolute;
height: 0;
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#80000000', endColorstr='#80000000') \0;
background: rgba(0, 0, 0, 0.5);
width: 100%;
top: 0;
left: 0;
overflow: hidden;
z-index: 300;
}
#upload .filelist div.file-panel span {
width: 24px;
height: 24px;
display: inline;
float: right;
text-indent: -9999px;
overflow: hidden;
background: url(./images/icons.png) no-repeat;
background: url(./images/icons.gif) no-repeat \9;
margin: 5px 1px 1px;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#upload .filelist div.file-panel span.rotateLeft {
display: none;
background-position: 0 -24px;
}
#upload .filelist div.file-panel span.rotateLeft:hover {
background-position: 0 0;
}
#upload .filelist div.file-panel span.rotateRight {
display: none;
background-position: -24px -24px;
}
#upload .filelist div.file-panel span.rotateRight:hover {
background-position: -24px 0;
}
#upload .filelist div.file-panel span.cancel {
background-position: -48px -24px;
}
#upload .filelist div.file-panel span.cancel:hover {
background-position: -48px 0;
}
#upload .statusBar {
height: 45px;
border-bottom: 1px solid #dadada;
margin: 0 10px;
padding: 0;
line-height: 45px;
vertical-align: middle;
position: relative;
}
#upload .statusBar .progress {
border: 1px solid #1483d8;
width: 198px;
background: #fff;
height: 18px;
position: absolute;
top: 12px;
display: none;
text-align: center;
line-height: 18px;
color: #6dbfff;
margin: 0 10px 0 0;
}
#upload .statusBar .progress span.percentage {
width: 0;
height: 100%;
left: 0;
top: 0;
background: #1483d8;
position: absolute;
}
#upload .statusBar .progress span.text {
position: relative;
z-index: 10;
}
#upload .statusBar .info {
display: inline-block;
font-size: 14px;
color: #666666;
}
#upload .statusBar .btns {
position: absolute;
top: 7px;
right: 0;
line-height: 30px;
}
#filePickerBtn {
display: inline-block;
float: left;
}
#upload .statusBar .btns .webuploader-pick,
#upload .statusBar .btns .uploadBtn,
#upload .statusBar .btns .uploadBtn.state-uploading,
#upload .statusBar .btns .uploadBtn.state-paused {
background: #ffffff;
border: 1px solid #cfcfcf;
color: #565656;
padding: 0 18px;
display: inline-block;
border-radius: 3px;
margin-left: 10px;
cursor: pointer;
font-size: 14px;
float: left;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#upload .statusBar .btns .webuploader-pick-hover,
#upload .statusBar .btns .uploadBtn:hover,
#upload .statusBar .btns .uploadBtn.state-uploading:hover,
#upload .statusBar .btns .uploadBtn.state-paused:hover {
background: #f0f0f0;
}
#upload .statusBar .btns .uploadBtn,
#upload .statusBar .btns .uploadBtn.state-paused {
background: #00b7ee;
color: #fff;
border-color: transparent;
}
#upload .statusBar .btns .uploadBtn:hover,
#upload .statusBar .btns .uploadBtn.state-paused:hover {
background: #00a2d4;
}
#upload .statusBar .btns .uploadBtn.disabled {
pointer-events: none;
filter: alpha(opacity=60);
-moz-opacity: 0.6;
-khtml-opacity: 0.6;
opacity: 0.6;
}
/* 图片管理样式 */
#online {
width: 100%;
height: 336px;
padding: 10px 0 0 0;
}
#online #imageList {
width: 100%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
position: relative;
}
#online ul {
display: block;
list-style: none;
margin: 0;
padding: 0;
}
#online li {
float: left;
display: block;
list-style: none;
padding: 0;
width: 113px;
height: 113px;
margin: 0 0 9px 9px;
*margin: 0 0 6px 6px;
background-color: #eee;
overflow: hidden;
cursor: pointer;
position: relative;
}
#online li.clearFloat {
float: none;
clear: both;
display: block;
width: 0;
height: 0;
margin: 0;
padding: 0;
}
#online li img {
cursor: pointer;
}
#online li .icon {
cursor: pointer;
width: 113px;
height: 113px;
position: absolute;
top: 0;
left: 0;
z-index: 2;
border: 0;
background-repeat: no-repeat;
}
#online li .icon:hover {
width: 107px;
height: 107px;
border: 3px solid #1094fa;
}
#online li.selected .icon {
background-image: url(images/success.png);
background-image: url(images/success.gif) \9;
background-position: 75px 75px;
}
#online li.selected .icon:hover {
width: 107px;
height: 107px;
border: 3px solid #1094fa;
background-position: 72px 72px;
}

View File

@@ -1,125 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>ueditor图片对话框</title>
<script type="text/javascript" src="../internal.js?aea0c61c"></script>
<!-- jquery -->
<script type="text/javascript" src="../../third-party/jquery-1.10.2.js?628072e7"></script>
<!-- webuploader -->
<script src="../../third-party/webuploader/webuploader.js?f37088cc"></script>
<link rel="stylesheet" type="text/css" href="../../third-party/webuploader/webuploader.css?0057c5c7">
<!-- image dialog -->
<link rel="stylesheet" href="image.css?fc461d7b" type="text/css"/>
</head>
<body>
<div class="wrapper">
<div id="tabhead" class="tabhead">
<span class="tab focus" data-content-id="remote"><var id="lang_tab_remote"></var></span>
<span style="display:none;" class="tab" data-content-id="upload"><var id="lang_tab_upload"></var></span>
<span style="display:none;" class="tab" data-content-id="online"><var id="lang_tab_online"></var></span>
</div>
<div class="alignBar">
<label class="algnLabel"><var id="lang_input_align"></var></label>
<span id="alignIcon">
<span id="noneAlign" class="none-align focus" data-align="none"></span>
<span id="leftAlign" class="left-align" data-align="left"></span>
<span id="rightAlign" class="right-align" data-align="right"></span>
<span id="centerAlign" class="center-align" data-align="center"></span>
</span>
<input id="align" name="align" type="hidden" value="none"/>
</div>
<div id="tabbody" class="tabbody">
<!-- 远程图片 -->
<div id="remote" class="panel">
<div class="top">
<div class="row">
<label for="url"><var id="lang_input_url"></var></label>
<span><input class="text" id="url" type="text"/></span>
<a href="javascript:;" id="imageSelect" style="display:none;">选择图片</a>
</div>
</div>
<div class="left">
<div class="row">
<label><var id="lang_input_size"></var></label>
<span><var id="lang_input_width">&nbsp;&nbsp;</var><input class="text" type="text"
id="width"/>px </span>
<span><var id="lang_input_height">&nbsp;&nbsp;</var><input class="text" type="text" id="height"/>px </span>
<span><input id="lock" type="checkbox" disabled="disabled"><span id="lockicon"></span></span>
</div>
<div class="row">
<label><var id="lang_input_border"></var></label>
<span><input class="text" type="text" id="border"/>px </span>
</div>
<div class="row">
<label><var id="lang_input_vhspace"></var></label>
<span><input class="text" type="text" id="vhSpace"/>px </span>
</div>
<div class="row">
<label><var id="lang_input_title"></var></label>
<span><input class="text" type="text" id="title"/></span>
</div>
</div>
<div class="right">
<div id="preview"></div>
</div>
</div>
<!-- 上传图片 -->
<div id="upload" class="panel focus">
<div id="queueList" class="queueList">
<div class="statusBar element-invisible">
<div class="progress">
<span class="text">0%</span>
<span class="percentage"></span>
</div>
<div class="info"></div>
<div class="btns">
<div id="filePickerBtn"></div>
<div class="uploadBtn"><var id="lang_start_upload"></var></div>
</div>
</div>
<div id="dndArea" class="placeholder">
<div class="filePickerContainer">
<div id="filePickerReady"></div>
</div>
</div>
<ul class="filelist element-invisible">
<li id="filePickerBlock" class="filePickerBlock"></li>
</ul>
</div>
</div>
<!-- 在线图片 -->
<div id="online" class="panel">
<div id="imageList"><var id="lang_imgLoading"></var></div>
</div>
<!-- 搜索图片 -->
<div id="search" class="panel">
<div class="searchBar">
<input id="searchTxt" class="searchTxt text" type="text"/>
<select id="searchType" class="searchType">
<option value="&s=4&z=0"></option>
<option value="&s=1&z=19"></option>
<option value="&s=2&z=0"></option>
<option value="&s=3&z=0"></option>
</select>
<input id="searchReset" type="button"/>
<input id="searchBtn" type="button"/>
</div>
<div id="searchList" class="searchList">
<ul id="searchListUl"></ul>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="image.js?a72fb84c"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

Some files were not shown because too many files have changed in this diff Show More