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接口正常响应
@@ -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 Token(swagger.token)。
|
||||
- 观测与健康:Winston 日志、Terminus 健康(/healthz /readyz /startupz)、Metrics 基础可用。
|
||||
- 任务与事件:Outbox(events)表、调度与重试字段/索引齐备;队列/事件基础设施在位。
|
||||
- 安全基线:全局守卫、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 反代模板:固化到仓库 docs(HTTPS/超时/限流/大包/真实 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(脚本已内置或通过环境变量)。
|
||||
@@ -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`;统一守卫与响应格式
|
||||
|
||||
|
||||
@@ -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的中间件方式更加灵活和类型安全,符合现代框架的设计理念。
|
||||
这种方式灵活且类型安全,符合现代框架的设计理念。
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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')}
|
||||
}`;
|
||||
) {}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()');
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ');
|
||||
}
|
||||
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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": []
|
||||
},
|
||||
|
||||
@@ -221,7 +221,9 @@ class NamingUtils {
|
||||
* 生成控制器名
|
||||
*/
|
||||
generateControllerName(componentName) {
|
||||
return this.toPascalCase(componentName) + 'Controller';
|
||||
// 先移除已有的 Controller 后缀,避免重复
|
||||
const cleanName = componentName.replace(/Controller$/, '');
|
||||
return this.toPascalCase(cleanName) + 'Controller';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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: [],
|
||||
})
|
||||
|
||||
@@ -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迁移工具自动生成
|
||||
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
56
wwjcloud-nest/.gitignore
vendored
@@ -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
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
@@ -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平台产品团队
|
||||
|
||||
---
|
||||
|
||||
⭐ 如果这个项目对你有帮助,请给它一个星星!
|
||||
@@ -1,15 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
npm-debug.log
|
||||
.env.local
|
||||
.env.*.local
|
||||
.git
|
||||
.gitignore
|
||||
.vscode
|
||||
.idea
|
||||
*.md
|
||||
!README.md
|
||||
test
|
||||
coverage
|
||||
.cache
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
24
wwjcloud-nest/admin/.gitignore
vendored
@@ -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?
|
||||
@@ -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;"]
|
||||
|
||||
@@ -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.
|
||||
7
wwjcloud-nest/admin/auto-imports.d.ts
vendored
@@ -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']
|
||||
}
|
||||
107
wwjcloud-nest/admin/components.d.ts
vendored
@@ -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']
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
})();
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 453 B |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 445 B |
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 453 B |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 445 B |
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -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;
|
||||
}
|
||||
@@ -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 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>
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
})();
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -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>
|
||||
@@ -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 () {
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 43 B |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 216 B |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 28 KiB |
@@ -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>
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"> </var><input class="text" type="text"
|
||||
id="width"/>px </span>
|
||||
<span><var id="lang_input_height"> </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>
|
||||
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 453 B |