mirror of
https://gitee.com/NexIoT/Universal-IoT-Java.git
synced 2026-10-31 00:41:27 +08:00
Binary file not shown.
+85
-68
@@ -199,8 +199,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
String type = bo.getType();
|
||||
String productKey = bo.getProductKey();
|
||||
String unionId = bo.getUnionId();
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
|
||||
.equals(type)) {
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
|| NetworkType.TCP_SERVER.getId().equals(type)) {
|
||||
if (tcpClusterService != null && tcpServerManager != null) {
|
||||
Object serverInstance = tcpServerManager.getServerInstance(productKey);
|
||||
if (serverInstance != null && tcpServerManager.isAlive(serverInstance)) {
|
||||
@@ -216,14 +216,14 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
}
|
||||
// 查出哪些TCP-Server绑定了产品
|
||||
if (NetworkType.TCP_SERVER.getId().equals(type)) {
|
||||
IoTProductBO ioTProductBO = ioTProductMapper.selectTcpProductsUseNetwork(
|
||||
bo.getProductKey());
|
||||
IoTProductBO ioTProductBO =
|
||||
ioTProductMapper.selectTcpProductsUseNetwork(bo.getProductKey());
|
||||
bo.setBindTcpServerProductCount(ioTProductBO == null ? 0 : 1);
|
||||
bo.setBindTcpServerProducts(ioTProductBO);
|
||||
}
|
||||
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
|
||||
.equals(type)) {
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type)
|
||||
|| NetworkType.MQTT_SERVER.getId().equals(type)) {
|
||||
List<IoTProductBO> ioTProductBOS = ioTProductMapper.selectMqttProductsUseNetwork(unionId);
|
||||
bo.setBindMqttServerProductCount(CollUtil.size(ioTProductBOS));
|
||||
bo.setBindMqttServerProducts(ioTProductBOS);
|
||||
@@ -294,8 +294,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
String type = network.getType();
|
||||
String productKey = network.getProductKey();
|
||||
String unionId = network.getUnionId();
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
|
||||
.equals(type)) {
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
|| NetworkType.TCP_SERVER.getId().equals(type)) {
|
||||
if (tcpClusterService != null && tcpServerManager != null) {
|
||||
Object serverInstance = tcpServerManager.getServerInstance(productKey);
|
||||
if (serverInstance != null && tcpServerManager.isAlive(serverInstance)) {
|
||||
@@ -310,8 +310,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
vo.setRunning(Boolean.FALSE);
|
||||
}
|
||||
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
|
||||
.equals(type)) {
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type)
|
||||
|| NetworkType.MQTT_SERVER.getId().equals(type)) {
|
||||
if (mqttServerManager != null && mqttServerManager.isConnected(unionId)) {
|
||||
vo.setStateName("已启动");
|
||||
vo.setRunning(Boolean.TRUE);
|
||||
@@ -348,8 +348,9 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
}
|
||||
// 常用端口
|
||||
Set<Integer> commonPorts = new HashSet<>();
|
||||
int[] arr = {80, 443, 3306, 6379, 8080, 22, 21, 25, 53, 123, 1521, 5432, 8888, 9000, 5000, 7001,
|
||||
27017};
|
||||
int[] arr = {
|
||||
80, 443, 3306, 6379, 8080, 22, 21, 25, 53, 123, 1521, 5432, 8888, 9000, 5000, 7001, 27017
|
||||
};
|
||||
for (int p : arr) {
|
||||
commonPorts.add(p);
|
||||
}
|
||||
@@ -389,8 +390,9 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
network.setState(false);
|
||||
|
||||
// 新增TCP_SERVER/UDP时,必须指定productKey,并且不能重复绑定
|
||||
if (NetworkType.TCP_SERVER.getId().equals(network.getType()) || NetworkType.TCP_CLIENT.getId()
|
||||
.equals(network.getType()) || NetworkType.UDP.getId().equals(network.getType())) {
|
||||
if (NetworkType.TCP_SERVER.getId().equals(network.getType())
|
||||
|| NetworkType.TCP_CLIENT.getId().equals(network.getType())
|
||||
|| NetworkType.UDP.getId().equals(network.getType())) {
|
||||
if (StrUtil.isBlank(network.getProductKey())) {
|
||||
throw new RuntimeException("TCP/UDP服务组件必须选择产品");
|
||||
}
|
||||
@@ -405,8 +407,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
int result = networkMapper.insertNetwork(network);
|
||||
// 新增成功后,若为TCP_SERVER,更新iot_product表
|
||||
if (result > 0 && NetworkType.TCP_SERVER.getId().equals(network.getType())) {
|
||||
ioTProductMapper.updateNetworkUnionIdByProductKey(network.getProductKey(),
|
||||
network.getProductKey());
|
||||
ioTProductMapper.updateNetworkUnionIdByProductKey(
|
||||
network.getProductKey(), network.getProductKey());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -432,7 +434,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
}
|
||||
|
||||
String type = existNetwork.getType();
|
||||
if ((NetworkType.TCP_SERVER.getId().equals(type) || NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
if ((NetworkType.TCP_SERVER.getId().equals(type)
|
||||
|| NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
|| NetworkType.UDP.getId().equals(type))) {
|
||||
// 只有当unionId发生变化时,才做"已被产品关联且产品下有设备时禁止修改"的校验
|
||||
String oldProductKey = existNetwork.getProductKey();
|
||||
@@ -450,8 +453,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
checkPortAvailable(network, true);
|
||||
int count = networkMapper.updateNetwork(network);
|
||||
if (count > 0 && NetworkType.TCP_SERVER.getId().equals(network.getType())) {
|
||||
ioTProductMapper.updateNetworkUnionIdByProductKey(network.getProductKey(),
|
||||
network.getProductKey());
|
||||
ioTProductMapper.updateNetworkUnionIdByProductKey(
|
||||
network.getProductKey(), network.getProductKey());
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -465,7 +468,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
}
|
||||
String type = network.getType();
|
||||
// 只对TCP_SERVER、TCP_CLIENT和UDP做判断
|
||||
if (NetworkType.TCP_SERVER.getId().equals(type) || NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
if (NetworkType.TCP_SERVER.getId().equals(type)
|
||||
|| NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
|| NetworkType.UDP.getId().equals(type)) {
|
||||
// 查找是否有关联产品
|
||||
String productKey = ioTProductMapper.findProductKeyByNetworkUnionId(network.getUnionId());
|
||||
@@ -495,14 +499,14 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
}
|
||||
String type = network.getType();
|
||||
JSONObject config = JSONUtil.parseObj(network.getConfiguration());
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
|
||||
.equals(type)) {
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
|| NetworkType.TCP_SERVER.getId().equals(type)) {
|
||||
Integer port = config.getInt("port");
|
||||
if (port == null) {
|
||||
throw new RuntimeException("TCP网络组件启动/重启时端口不能为空");
|
||||
}
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
|
||||
.equals(type)) {
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type)
|
||||
|| NetworkType.MQTT_SERVER.getId().equals(type)) {
|
||||
String host = config.getStr("host");
|
||||
if (StrUtil.isBlank(host)) {
|
||||
throw new RuntimeException("MQTT网络组件启动/重启时host不能为空");
|
||||
@@ -521,7 +525,7 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
log.info("启动网络组件成功: {}", network.getName());
|
||||
return 1;
|
||||
} else {
|
||||
throw new RuntimeException("启动失败: " + network.getName());
|
||||
throw new IoTException("系统协议类型模块不存在,请检查");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("启动网络组件失败: {}", network.getName(), e);
|
||||
@@ -561,14 +565,14 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
}
|
||||
String type = network.getType();
|
||||
JSONObject config = JSONUtil.parseObj(network.getConfiguration());
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId()
|
||||
.equals(type)) {
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
|| NetworkType.TCP_SERVER.getId().equals(type)) {
|
||||
Integer port = config.getInt("port");
|
||||
if (port == null) {
|
||||
throw new RuntimeException("TCP网络组件启动/重启时端口不能为空");
|
||||
}
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
|
||||
.equals(type)) {
|
||||
} else if (NetworkType.MQTT_CLIENT.getId().equals(type)
|
||||
|| NetworkType.MQTT_SERVER.getId().equals(type)) {
|
||||
String host = config.getStr("host");
|
||||
if (StrUtil.isBlank(host)) {
|
||||
throw new RuntimeException("MQTT网络组件启动/重启时host不能为空");
|
||||
@@ -598,8 +602,12 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
|
||||
@Override
|
||||
public List<String> getNetworkTypes() {
|
||||
return Arrays.asList(NetworkType.TCP_CLIENT.getId(), NetworkType.TCP_SERVER.getId(),
|
||||
NetworkType.MQTT_CLIENT.getId(), NetworkType.MQTT_SERVER.getId(), NetworkType.UDP.getId());
|
||||
return Arrays.asList(
|
||||
NetworkType.TCP_CLIENT.getId(),
|
||||
NetworkType.TCP_SERVER.getId(),
|
||||
NetworkType.MQTT_CLIENT.getId(),
|
||||
NetworkType.MQTT_SERVER.getId(),
|
||||
NetworkType.UDP.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -660,7 +668,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
JSONObject config = JSONUtil.parseObj(network.getConfiguration());
|
||||
String type = network.getType();
|
||||
// TCP/UDP类型检查端口唯一性
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type) || NetworkType.TCP_SERVER.getId().equals(type)
|
||||
if (NetworkType.TCP_CLIENT.getId().equals(type)
|
||||
|| NetworkType.TCP_SERVER.getId().equals(type)
|
||||
|| NetworkType.UDP.getId().equals(type)) {
|
||||
Integer port = config.getInt("port");
|
||||
if (port != null) {
|
||||
@@ -674,18 +683,24 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
}
|
||||
|
||||
// MQTT类型检查主机和用户名组合唯一性
|
||||
if (NetworkType.MQTT_CLIENT.getId().equals(type) || NetworkType.MQTT_SERVER.getId()
|
||||
.equals(type)) {
|
||||
if (NetworkType.MQTT_CLIENT.getId().equals(type)
|
||||
|| NetworkType.MQTT_SERVER.getId().equals(type)) {
|
||||
String host = config.getStr("host");
|
||||
String username = config.getStr("username");
|
||||
|
||||
if (StrUtil.isNotBlank(host) && StrUtil.isNotBlank(username)) {
|
||||
List<Network> existingNetworks = networkMapper.selectMqttNetworkByHostAndUsername(host,
|
||||
username, excludeId);
|
||||
List<Network> existingNetworks =
|
||||
networkMapper.selectMqttNetworkByHostAndUsername(host, username, excludeId);
|
||||
if (!existingNetworks.isEmpty()) {
|
||||
Network existingNetwork = existingNetworks.get(0);
|
||||
throw new RuntimeException("主机 " + host + " 和用户名 " + username + " 的组合已被 "
|
||||
+ existingNetwork.getName() + " 网络组件使用");
|
||||
throw new RuntimeException(
|
||||
"主机 "
|
||||
+ host
|
||||
+ " 和用户名 "
|
||||
+ username
|
||||
+ " 的组合已被 "
|
||||
+ existingNetwork.getName()
|
||||
+ " 网络组件使用");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,24 +720,18 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
*/
|
||||
private boolean startNetworkByType(Network network) {
|
||||
String type = network.getType();
|
||||
|
||||
try {
|
||||
switch (type) {
|
||||
case NetworkTypeConstants.TCP_CLIENT:
|
||||
case NetworkTypeConstants.TCP_SERVER:
|
||||
return startTcpNetwork(network);
|
||||
case NetworkTypeConstants.MQTT_CLIENT:
|
||||
case NetworkTypeConstants.MQTT_SERVER:
|
||||
return startMqttNetwork(network);
|
||||
case NetworkTypeConstants.UDP:
|
||||
return startUdpNetwork(network);
|
||||
default:
|
||||
log.warn("不支持的网络类型: {}", type);
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("启动网络组件失败: type={}, name={}", type, network.getName(), e);
|
||||
return false;
|
||||
switch (type) {
|
||||
case NetworkTypeConstants.TCP_CLIENT:
|
||||
case NetworkTypeConstants.TCP_SERVER:
|
||||
return startTcpNetwork(network);
|
||||
case NetworkTypeConstants.MQTT_CLIENT:
|
||||
case NetworkTypeConstants.MQTT_SERVER:
|
||||
return startMqttNetwork(network);
|
||||
case NetworkTypeConstants.UDP:
|
||||
return startUdpNetwork(network);
|
||||
default:
|
||||
log.warn("不支持的网络类型: {}", type);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -792,7 +801,7 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
private boolean startTcpNetwork(Network network) {
|
||||
if (tcpClusterService == null) {
|
||||
log.error("TCP服务管理器未注入,无法启动TCP网络组件: {}", network.getName());
|
||||
return false;
|
||||
throw new IoTException("TCP模块未注入,无法启动TCP网络组件");
|
||||
}
|
||||
|
||||
String productKey = network.getProductKey();
|
||||
@@ -824,8 +833,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
*/
|
||||
private boolean stopTcpNetwork(Network network) {
|
||||
if (tcpClusterService == null) {
|
||||
log.error("TCP服务管理器未注入,无法停止TCP网络组件: {}", network.getName());
|
||||
return false;
|
||||
log.error("TCP服务管理器未注入,无法启动TCP网络组件: {}", network.getName());
|
||||
throw new IoTException("TCP模块未注入,无法启动TCP网络组件");
|
||||
}
|
||||
|
||||
String productKey = network.getProductKey();
|
||||
@@ -856,8 +865,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
*/
|
||||
private boolean restartTcpNetwork(Network network) {
|
||||
if (tcpClusterService == null) {
|
||||
log.error("TCP服务管理器未注入,无法重启TCP网络组件: {}", network.getName());
|
||||
return false;
|
||||
log.error("TCP服务管理器未注入,无法启动TCP网络组件: {}", network.getName());
|
||||
throw new IoTException("TCP模块未注入,无法启动TCP网络组件");
|
||||
}
|
||||
|
||||
String productKey = network.getProductKey();
|
||||
@@ -888,8 +897,7 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
*/
|
||||
private boolean startMqttNetwork(Network network) {
|
||||
if (mqttServerManager == null) {
|
||||
log.error("MQTT服务管理器未注入,无法启动MQTT网络组件: {}", network.getName());
|
||||
return false;
|
||||
throw new IoTException("MQTT模块未注入,无法启动TCP网络组件");
|
||||
}
|
||||
|
||||
String unionId = network.getUnionId();
|
||||
@@ -920,10 +928,8 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
*/
|
||||
private boolean stopMqttNetwork(Network network) {
|
||||
if (mqttServerManager == null) {
|
||||
log.error("MQTT服务管理器未注入,无法停止MQTT网络组件: {}", network.getName());
|
||||
return false;
|
||||
throw new IoTException("MQTT模块未注入,无法启动TCP网络组件");
|
||||
}
|
||||
|
||||
String unionId = network.getUnionId();
|
||||
if (StrUtil.isBlank(unionId)) {
|
||||
log.error("MQTT网络组件缺少unionId: {}", network.getName());
|
||||
@@ -952,8 +958,7 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
*/
|
||||
private boolean restartMqttNetwork(Network network) {
|
||||
if (mqttServerManager == null) {
|
||||
log.error("MQTT服务管理器未注入,无法重启MQTT网络组件: {}", network.getName());
|
||||
return false;
|
||||
throw new IoTException("MQTT模块未注入,无法启动TCP网络组件");
|
||||
}
|
||||
|
||||
String unionId = network.getUnionId();
|
||||
@@ -988,6 +993,10 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
* @return 是否成功
|
||||
*/
|
||||
private boolean startUdpNetwork(Network network) {
|
||||
if (udpClusterService == null) {
|
||||
log.error("UDP服务管理器未注入,无法启动TCP网络组件: {}", network.getName());
|
||||
throw new IoTException("UDP模块未注入,无法启动UDP网络组件");
|
||||
}
|
||||
String productKey = network.getProductKey();
|
||||
if (StrUtil.isBlank(productKey)) {
|
||||
log.error("UDP网络组件缺少productKey: {}", network.getName());
|
||||
@@ -1018,6 +1027,10 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
* @return 是否成功
|
||||
*/
|
||||
private boolean stopUdpNetwork(Network network) {
|
||||
if (udpClusterService == null) {
|
||||
log.error("UDP服务管理器未注入,无法启动TCP网络组件: {}", network.getName());
|
||||
throw new IoTException("UDP模块未注入,无法启动UDP网络组件");
|
||||
}
|
||||
String productKey = network.getProductKey();
|
||||
if (StrUtil.isBlank(productKey)) {
|
||||
log.error("UDP网络组件缺少productKey: {}", network.getName());
|
||||
@@ -1048,6 +1061,10 @@ public class NetworkServiceImpl implements INetworkService {
|
||||
* @return 是否成功
|
||||
*/
|
||||
private boolean restartUdpNetwork(Network network) {
|
||||
if (udpClusterService == null) {
|
||||
log.error("UDP服务管理器未注入,无法启动TCP网络组件: {}", network.getName());
|
||||
throw new IoTException("UDP模块未注入,无法启动UDP网络组件");
|
||||
}
|
||||
String productKey = network.getProductKey();
|
||||
if (StrUtil.isBlank(productKey)) {
|
||||
log.error("UDP网络组件缺少productKey: {}", network.getName());
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not ie <= 10
|
||||
@@ -0,0 +1,34 @@
|
||||
# 排除源代码和开发文件
|
||||
src/
|
||||
node_modules/
|
||||
package*.json
|
||||
webpack.config.js
|
||||
vite.config.js
|
||||
tsconfig.json
|
||||
.eslintrc.js
|
||||
.prettierrc
|
||||
|
||||
# 排除 IDE 文件
|
||||
.idea/
|
||||
.vscode/
|
||||
*.iml
|
||||
|
||||
# 排除版本控制文件
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# 排除构建产物 (只保留 dist 目录)
|
||||
!dist/
|
||||
|
||||
# 排除日志文件
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# 排除环境文件
|
||||
.env
|
||||
.env.local
|
||||
.env.development
|
||||
.env.test
|
||||
.env.production
|
||||
@@ -0,0 +1,39 @@
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = false
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{*.ng,*.sht,*.html,*.shtm,*.shtml,*.htm}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{.babelrc,.stylelintrc,jest.config,.eslintrc,.prettierrc,*.json,*.jsb3,*.jsb2,*.bowerrc}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.svg]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.js.map]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.less]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.vue]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{.analysis_options,*.yml,*.yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_PREVIEW=false
|
||||
VUE_APP_BASE_API=/api
|
||||
@@ -0,0 +1,7 @@
|
||||
NODE_ENV=development
|
||||
VUE_APP_PREVIEW=true
|
||||
VUE_APP_BASE_API=/api
|
||||
# VUE_APP_API_PATH = http://192.168.31.194:9092
|
||||
# VUE_APP_API_PATH = http://127.0.0.1:9091
|
||||
VUE_APP_API_PATH = http://127.0.0.1:9092
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
NODE_ENV=production
|
||||
VUE_APP_PREVIEW=false
|
||||
VUE_APP_BASE_API=/api
|
||||
@@ -0,0 +1,7 @@
|
||||
docs/
|
||||
node_modules
|
||||
dist/
|
||||
tests/
|
||||
build/
|
||||
vue.config.js
|
||||
public/
|
||||
@@ -0,0 +1,67 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: ['plugin:vue/strongly-recommended', '@vue/standard'],
|
||||
globals: {
|
||||
AMap: true,
|
||||
AMapUI: true,
|
||||
},
|
||||
rules: {
|
||||
'no-console': 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'generator-star-spacing': 'off',
|
||||
'no-mixed-operators': 0,
|
||||
'no-trailing-spaces': 'off',
|
||||
'no-multiple-empty-lines': 'off',
|
||||
'vue/max-attributes-per-line': 'off',
|
||||
'vue/attribute-hyphenation': 0,
|
||||
'vue/html-self-closing': 0,
|
||||
'vue/component-name-in-template-casing': 0,
|
||||
'vue/html-closing-bracket-spacing': 0,
|
||||
'vue/singleline-html-element-content-newline': 0,
|
||||
'vue/no-unused-components': 0,
|
||||
'vue/multiline-html-element-content-newline': 0,
|
||||
'vue/no-use-v-if-with-v-for': 0,
|
||||
'vue/html-closing-bracket-newline': 0,
|
||||
'vue/no-parsing-error': 0,
|
||||
'no-tabs': 0,
|
||||
quotes: [
|
||||
2,
|
||||
'single',
|
||||
{
|
||||
avoidEscape: true,
|
||||
allowTemplateLiterals: true,
|
||||
},
|
||||
],
|
||||
semi: [
|
||||
2,
|
||||
'never',
|
||||
{
|
||||
beforeStatementContinuationChars: 'never',
|
||||
},
|
||||
],
|
||||
'no-delete-var': 2,
|
||||
'prefer-const': [
|
||||
2,
|
||||
{
|
||||
ignoreReadBeforeAssign: false,
|
||||
},
|
||||
],
|
||||
'template-curly-spacing': 'off',
|
||||
indent: 'off',
|
||||
},
|
||||
parserOptions: {
|
||||
parser: '@babel/eslint-parser',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/__tests__/*.{j,t}s?(x)',
|
||||
'**/tests/unit/**/*.spec.{j,t}s?(x)'],
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
public/* linguist-vendored
|
||||
@@ -0,0 +1,25 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw*
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
@@ -0,0 +1 @@
|
||||
_
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"prettier.spaceBeforeFunctionParen": true
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
# SpecStory Artifacts Directory
|
||||
|
||||
This directory is automatically created and maintained by the SpecStory extension to preserve your
|
||||
AI chat history.
|
||||
|
||||
## What's Here?
|
||||
|
||||
- `.specstory/history`: Contains auto-saved markdown files of your AI coding sessions
|
||||
- Each file represents a separate AI chat session
|
||||
- If you enable auto-save, files are automatically updated as you work
|
||||
- You can enable/disable the auto-save feature in the SpecStory settings, it is disabled by
|
||||
default
|
||||
- `.specstory/.project.json`: Contains the persistent project identity for the current workspace
|
||||
- This file is only present if you enable AI rules derivation
|
||||
- This is used to provide consistent project identity of your project, even as the workspace is
|
||||
moved or renamed
|
||||
- `.specstory/ai_rules_backups`: Contains backups of the `.cursor/rules/derived-cursor-rules.mdc` or
|
||||
the `.github/copilot-instructions.md` file
|
||||
- Backups are automatically created each time the `.cursor/rules/derived-cursor-rules.mdc` or the
|
||||
`.github/copilot-instructions.md` file is updated
|
||||
- You can enable/disable the AI Rules derivation feature in the SpecStory settings, it is disabled
|
||||
by default
|
||||
- `.specstory/.gitignore`: Contains directives to exclude non-essential contents of the `.specstory`
|
||||
directory from version control
|
||||
- Add `/history` to exclude the auto-saved chat history from version control
|
||||
|
||||
## Valuable Uses
|
||||
|
||||
- Capture: Keep your context window up-to-date when starting new Chat/Composer sessions via @
|
||||
references
|
||||
- Search: For previous prompts and code snippets
|
||||
- Learn: Meta-analyze your patterns and learn from your past experiences
|
||||
- Derive: Keep the AI on course with your past decisions by automatically deriving rules from your
|
||||
AI interactions
|
||||
|
||||
## Version Control
|
||||
|
||||
We recommend keeping this directory under version control to maintain a history of your AI
|
||||
interactions. However, if you prefer not to version these files, you can exclude them by adding this
|
||||
to your `.gitignore`:
|
||||
|
||||
```
|
||||
.specstory/**
|
||||
```
|
||||
|
||||
We recommend __not__ keeping the `.specstory/ai_rules_backups` directory under version control if
|
||||
you are already using git to version your AI rules, and committing regularly. You can exclude it by
|
||||
adding this to your `.gitignore`:
|
||||
|
||||
```
|
||||
.specstory/ai_rules_backups
|
||||
```
|
||||
|
||||
## Searching Your Codebase
|
||||
|
||||
When searching your codebase, search results may include your previous AI coding interactions. To
|
||||
focus solely on your actual code files, you can exclude the AI interaction history from search
|
||||
results.
|
||||
|
||||
To exclude AI interaction history:
|
||||
|
||||
1. Open the "Find in Files" search in Cursor or VSCode (Cmd/Ctrl + Shift + F)
|
||||
2. Navigate to the "files to exclude" section
|
||||
3. Add the following pattern:
|
||||
|
||||
```
|
||||
.specstory/*
|
||||
```
|
||||
|
||||
This will ensure your searches only return results from your working codebase files.
|
||||
|
||||
## Notes
|
||||
|
||||
- Auto-save only works when Cursor or VSCode flushes sqlite database data to disk. This results in a
|
||||
small delay after the AI response is complete before SpecStory can save the history.
|
||||
|
||||
## Settings
|
||||
|
||||
You can control auto-saving behavior in Cursor or VSCode:
|
||||
|
||||
1. Open Cursor/Code → Settings → VS Code Settings (Cmd/Ctrl + ,)
|
||||
2. Search for "SpecStory"
|
||||
3. Find "Auto Save" setting to enable/disable
|
||||
|
||||
Auto-save occurs when changes are detected in the sqlite database, or every 2 minutes as a safety
|
||||
net.
|
||||
@@ -0,0 +1,7 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 10.15.0
|
||||
cache: yarn
|
||||
script:
|
||||
- yarn
|
||||
- yarn run lint --no-fix && yarn run build
|
||||
@@ -0,0 +1,18 @@
|
||||
# 使用 nginx 作为基础镜像
|
||||
FROM nginx:alpine
|
||||
|
||||
# 复制前端构建文件
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
|
||||
# 复制 nginx 配置
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:80/ || exit 1
|
||||
|
||||
# 启动 nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,31 @@
|
||||
# 使用 CentOS 作为基础镜像
|
||||
FROM centos:8
|
||||
|
||||
# 安装 nginx 和必要工具
|
||||
RUN yum update -y && yum install -y \
|
||||
nginx \
|
||||
curl \
|
||||
wget \
|
||||
&& yum clean all
|
||||
|
||||
# 复制前端构建文件
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
|
||||
# 复制 nginx 配置
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# 创建必要的目录
|
||||
RUN mkdir -p /var/log/nginx /var/cache/nginx
|
||||
|
||||
# 设置权限
|
||||
RUN chown -R nginx:nginx /usr/share/nginx/html /var/log/nginx /var/cache/nginx
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:80/health || exit 1
|
||||
|
||||
# 启动 nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,31 @@
|
||||
# 使用已经下载的 openjdk:21 镜像作为基础,安装 nginx
|
||||
FROM openjdk:21
|
||||
|
||||
# 安装 nginx 和必要工具
|
||||
RUN microdnf update -y && microdnf install -y \
|
||||
nginx \
|
||||
curl \
|
||||
wget \
|
||||
&& microdnf clean all
|
||||
|
||||
# 复制前端构建文件
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
|
||||
# 复制 nginx 配置
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# 创建必要的目录
|
||||
RUN mkdir -p /var/log/nginx /var/cache/nginx
|
||||
|
||||
# 设置权限
|
||||
RUN chown -R nginx:nginx /usr/share/nginx/html /var/log/nginx /var/cache/nginx
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:80/health || exit 1
|
||||
|
||||
# 启动 nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,18 @@
|
||||
# 使用 Python 内置 HTTP 服务器作为最简单的静态文件服务
|
||||
FROM python:3.11-slim
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 复制前端构建文件
|
||||
COPY dist/ ./
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:80/health || exit 1
|
||||
|
||||
# 启动 Python HTTP 服务器
|
||||
CMD ["python", "-m", "http.server", "80"]
|
||||
@@ -0,0 +1,31 @@
|
||||
# 使用 Ubuntu 作为基础镜像
|
||||
FROM ubuntu:22.04
|
||||
|
||||
# 安装 nginx 和必要工具
|
||||
RUN apt-get update && apt-get install -y \
|
||||
nginx \
|
||||
curl \
|
||||
wget \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 复制前端构建文件
|
||||
COPY dist/ /var/www/html/
|
||||
|
||||
# 复制 nginx 配置
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
# 创建必要的目录
|
||||
RUN mkdir -p /var/log/nginx /var/cache/nginx
|
||||
|
||||
# 设置权限
|
||||
RUN chown -R www-data:www-data /var/www/html /var/log/nginx /var/cache/nginx
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 80
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost:80/health || exit 1
|
||||
|
||||
# 启动 nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 扶醉
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,129 @@
|
||||
<h1 align="center">RuoYi-Antdv</h1>
|
||||
|
||||
> RuoYi-Antdv 是RuoYi-Vue和Ant Design Vue Pro的结合。
|
||||
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/fuzui/RuoYi-Antdv" target="_blank"><img src="https://gitee.com/fuzui/RuoYi-Antdv/badge/star.svg?theme=dark" alt="Build Status"></a>
|
||||
<a href="https://github.com/fuzui/RuoYi-Antdv" target="_blank"><img src="https://img.shields.io/github/stars/fuzui/RuoYi-Antdv.svg?style=social" alt="Build Status"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue" target="_blank"><img src="https://img.shields.io/badge/RuoYi Vue-3.8.0-brightgreen" alt="Build Status"></a>
|
||||
<a href="https://github.com/vueComponent/ant-design-vue" target="_blank"><img src="https://img.shields.io/badge/Ant Design Vue-1.7.8-brightgreen" alt="Build Status"></a>
|
||||
</p>
|
||||
|
||||
|
||||
------------------------------
|
||||
|
||||
## 简介
|
||||
|
||||
**RuoYi-Antdv**,使用[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)作为后端,改其原有Element
|
||||
Ui为Ant Design Vue。将会持续完全适配RuoYi-Vue。
|
||||
|
||||
> RuoYi-Vue是基于SpringBoot,Spring Security,JWT,Vue 的前后端分离权限管理系统。
|
||||
>
|
||||
> 拥有用户管理、部门管理、岗位管理、菜单管理、角色管理、字典管理、参数管理、通知公告、操作日志、登录日志、在线用户、定时任务、代码生成、系统接口、服务监控、在线构建器、连接池监视等功能。
|
||||
|
||||
*当前暂不支持RuoYi中的在线构建器功能。*
|
||||
|
||||
* 预览:[https://ruoyi.setworld.net/](https://ruoyi.setworld.net/)
|
||||
|
||||
* 文档:[https://docs.geekera.cn/RuoYi-Antdv/](https://docs.geekera.cn/RuoYi-Antdv/)
|
||||
|
||||
* RuoYi-Vue文档:[https://doc.ruoyi.vip/ruoyi-vue/](https://doc.ruoyi.vip/ruoyi-vue/)
|
||||
|
||||
* Ant Design
|
||||
Vue文档:[https://www.antdv.com/docs/vue/introduce-cn/](https://www.antdv.com/docs/vue/introduce-cn/)
|
||||
|
||||
## 开始使用
|
||||
|
||||
1. 环境准备
|
||||
|
||||
* 运行启动RuoYi-Vue,参考[RuoYi文档](https://doc.ruoyi.vip/ruoyi-vue/)
|
||||
* 安装[node](http://nodejs.org/)和[git](https://git-scm.com/)
|
||||
|
||||
2. 安装
|
||||
|
||||
```shell
|
||||
git clone git@gitee.com:fuzui/RuoYi-Antdv.git
|
||||
```
|
||||
|
||||
或
|
||||
|
||||
```shell
|
||||
git clone git@github.com:fuzui/RuoYi-Antdv.git
|
||||
```
|
||||
|
||||
3. 本地开发
|
||||
|
||||
进入项目根目录
|
||||
|
||||
```shell
|
||||
npm install
|
||||
```
|
||||
|
||||
> 若耗时太长可使用`npm install --registry=https://registry.npm.taobao.org`
|
||||
|
||||
```shell
|
||||
npm run serve
|
||||
```
|
||||
|
||||
> 打开浏览器访问 [http://localhost:8000](http://localhost:8080/)
|
||||
|
||||
4. 部署
|
||||
|
||||
[RuoYi-Antdv部署](https://docs.geekera.cn/RuoYi-Antdv/use.html)
|
||||
|
||||
## 注意事项
|
||||
|
||||
* 若需使用代码生成,请按照文档描述修改:
|
||||
[代码生成前端适配](./docs/gen/)
|
||||
|
||||
## 致谢
|
||||
|
||||
* [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) 基于SpringBoot,Spring Security,JWT,Vue
|
||||
的前后端分离权限管理系统
|
||||
* [Ant Design Vue](https://github.com/vueComponent/ant-design-vue/) An enterprise-class UI
|
||||
components based on Ant Design and Vue
|
||||
* [Ant Design Vue Pro](https://github.com/vueComponent/ant-design-vue-pro) Use Ant Design Vue like a
|
||||
Pro
|
||||
* [wangEditor](https://github.com/wangeditor-team/wangEditor) 轻量级web富文本框
|
||||
|
||||
## 推荐
|
||||
|
||||
* [RuoYi-Cloud-Ant-Design](https://gitee.com/xuezipeng/ruoyi-cloud-ant-design) RuoYi-Cloud的Ant
|
||||
Design(Antdv)版前端
|
||||
|
||||
* [RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) 基于Spring Boot、Spring Cloud &
|
||||
Alibaba的分布式微服务架构权限管理系统
|
||||
|
||||
## 联系
|
||||
|
||||
如果您发现了什么bug,或者有什么界面建议或意见,
|
||||
|
||||
欢迎 [issue](https://github.com/fuzui/RuoYi-Antdv/issues)
|
||||
|
||||
`RuoYi-Antdv(SpringBoot/SpringCloud)`群:
|
||||
|
||||
[](https://jq.qq.com/?_wv=1027&k=Cq8fZnrj)
|
||||
|
||||
如果讨论后端,推荐添加若依前后端分离交流群(官方):
|
||||
|
||||
[](https://jq.qq.com/?_wv=1027&k=UKtX5jhs)
|
||||
|
||||
## 演示图
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://oss.fuzui.net/img/20210102022024.png"/></td>
|
||||
<td><img src="https://oss.fuzui.net/img/20210102022136.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oss.fuzui.net/img/20210102022247.png"/></td>
|
||||
<td><img src="https://oss.fuzui.net/img/20210102022534.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oss.fuzui.net/img/20210102022749.png"/></td>
|
||||
<td><img src="https://oss.fuzui.net/img/20210102023153.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
const IS_PROD = ['production', 'prod'].includes(process.env.NODE_ENV)
|
||||
|
||||
const plugins = []
|
||||
if (IS_PROD) {
|
||||
plugins.push('transform-remove-console')
|
||||
}
|
||||
|
||||
// lazy load ant-design-vue
|
||||
// if your use import on Demand, Use this code
|
||||
plugins.push(['import', {
|
||||
'libraryName': 'ant-design-vue',
|
||||
'libraryDirectory': 'es',
|
||||
'style': true // `style: true` 会加载 less 文件
|
||||
}])
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
'useBuiltIns': 'entry',
|
||||
'corejs': 3
|
||||
}
|
||||
]
|
||||
],
|
||||
plugins
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
const ThemeColorReplacer = require('webpack-theme-color-replacer')
|
||||
const generate = require('@ant-design/colors').generate
|
||||
|
||||
const getAntdSerials = (color) => {
|
||||
// 淡化(即less的tint)
|
||||
const lightens = new Array(9).fill().map((t, i) => {
|
||||
return ThemeColorReplacer.varyColor.lighten(color, i / 10)
|
||||
})
|
||||
const colorPalettes = generate(color)
|
||||
const rgb = ThemeColorReplacer.varyColor.toNum3(color.replace('#', '')).join(
|
||||
',')
|
||||
return lightens.concat(colorPalettes).concat(rgb)
|
||||
}
|
||||
|
||||
const themePluginOption = {
|
||||
fileName: 'css/theme-colors-[contenthash:8].css',
|
||||
matchColors: getAntdSerials('#1890ff'), // 主色系列
|
||||
// 改变样式选择器,解决样式覆盖问题
|
||||
changeSelector(selector) {
|
||||
switch (selector) {
|
||||
case '.ant-calendar-today .ant-calendar-date':
|
||||
return ':not(.ant-calendar-selected-date):not(.ant-calendar-selected-day)'
|
||||
+ selector
|
||||
case '.ant-btn:focus,.ant-btn:hover':
|
||||
return '.ant-btn:focus:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:hover:not(.ant-btn-primary):not(.ant-btn-danger)'
|
||||
case '.ant-btn.active,.ant-btn:active':
|
||||
return '.ant-btn.active:not(.ant-btn-primary):not(.ant-btn-danger),.ant-btn:active:not(.ant-btn-primary):not(.ant-btn-danger)'
|
||||
case '.ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon':
|
||||
case '.ant-steps-item-process .ant-steps-item-icon>.ant-steps-icon':
|
||||
return ':not(.ant-steps-item-process)' + selector
|
||||
// fixed https://github.com/vueComponent/ant-design-vue-pro/issues/876
|
||||
case '.ant-steps-item-process .ant-steps-item-icon':
|
||||
return ':not(.ant-steps-item-custom)' + selector
|
||||
case '.ant-menu-horizontal>.ant-menu-item-active,.ant-menu-horizontal>.ant-menu-item-open,.ant-menu-horizontal>.ant-menu-item-selected,.ant-menu-horizontal>.ant-menu-item:hover,.ant-menu-horizontal>.ant-menu-submenu-active,.ant-menu-horizontal>.ant-menu-submenu-open,.ant-menu-horizontal>.ant-menu-submenu-selected,.ant-menu-horizontal>.ant-menu-submenu:hover':
|
||||
case '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal > .ant-menu-submenu-selected,.ant-menu-horizontal > .ant-menu-submenu:hover':
|
||||
return '.ant-menu-horizontal > .ant-menu-item-active,.ant-menu-horizontal > .ant-menu-item-open,.ant-menu-horizontal > .ant-menu-item-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-item:hover,.ant-menu-horizontal > .ant-menu-submenu-active,.ant-menu-horizontal > .ant-menu-submenu-open,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu-selected,.ant-menu-horizontal:not(.ant-menu-dark) > .ant-menu-submenu:hover'
|
||||
case '.ant-menu-horizontal > .ant-menu-item-selected > a':
|
||||
case '.ant-menu-horizontal>.ant-menu-item-selected>a':
|
||||
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item-selected > a'
|
||||
case '.ant-menu-horizontal > .ant-menu-item > a:hover':
|
||||
case '.ant-menu-horizontal>.ant-menu-item>a:hover':
|
||||
return '.ant-menu-horizontal:not(ant-menu-light):not(.ant-menu-dark) > .ant-menu-item > a:hover'
|
||||
default :
|
||||
return selector
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const createThemeColorReplacerPlugin = () => new ThemeColorReplacer(
|
||||
themePluginOption)
|
||||
|
||||
module.exports = createThemeColorReplacerPlugin
|
||||
@@ -0,0 +1,115 @@
|
||||
export default {
|
||||
theme: [
|
||||
{
|
||||
key: 'dark',
|
||||
fileName: 'dark.css',
|
||||
theme: 'dark'
|
||||
},
|
||||
{
|
||||
key: '#F5222D',
|
||||
fileName: '#F5222D.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#F5222D'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#FA541C',
|
||||
fileName: '#FA541C.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#FA541C'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#FAAD14',
|
||||
fileName: '#FAAD14.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#FAAD14'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#13C2C2',
|
||||
fileName: '#13C2C2.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#13C2C2'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#52C41A',
|
||||
fileName: '#52C41A.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#52C41A'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#2F54EB',
|
||||
fileName: '#2F54EB.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#2F54EB'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#722ED1',
|
||||
fileName: '#722ED1.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#722ED1'
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
key: '#F5222D',
|
||||
theme: 'dark',
|
||||
fileName: 'dark-#F5222D.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#F5222D'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#FA541C',
|
||||
theme: 'dark',
|
||||
fileName: 'dark-#FA541C.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#FA541C'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#FAAD14',
|
||||
theme: 'dark',
|
||||
fileName: 'dark-#FAAD14.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#FAAD14'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#13C2C2',
|
||||
theme: 'dark',
|
||||
fileName: 'dark-#13C2C2.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#13C2C2'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#52C41A',
|
||||
theme: 'dark',
|
||||
fileName: 'dark-#52C41A.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#52C41A'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#2F54EB',
|
||||
theme: 'dark',
|
||||
fileName: 'dark-#2F54EB.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#2F54EB'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: '#722ED1',
|
||||
theme: 'dark',
|
||||
fileName: 'dark-#722ED1.css',
|
||||
modifyVars: {
|
||||
'@primary-color': '#722ED1'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
为首屏增加 加载动画
|
||||
====
|
||||
|
||||
## 需求
|
||||
|
||||
> 为了缓解用户第一次访问时,加载 JS 过大所导致用户等待白屏时间过长导致的用户体验不好,进行的一个优化动效。
|
||||
|
||||
## 实现方案
|
||||
|
||||
1. 将 动画加载 dom 元素放在 #app 内,Vue 生命周期开始时,会自动清掉 #app 下的所有元素。
|
||||
2. 将 动画加载 dom 元素放在 body 下,Vue 生命周期开始时 App.vue (created, mounted) 调用
|
||||
`@/utils/utll` 下的 removeLoadingAnimate(#id, timeout) 则会移除加载动画
|
||||
|
||||
最后一步:
|
||||
将样式插入到 `public/index.html` 文件的 `<head></head>` 最好写成内联 `<style>动画样式</style>`
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
目前提供有两个样式,均在 `public/loading` 文件夹内。且 pro 已经默认使用了一套 loading 动画方案,可以直接参考
|
||||
`public/index.html`
|
||||
|
||||
## 写在最后
|
||||
|
||||
目前 pro 有页面 overflow 显示出浏览器滚动条时,页面会抖动一下的问题。
|
||||
|
||||
欢迎各位提供能解决的方案和实现 demo。如果在条件允许的情况下,建议请直接使用 pro 进行改造,也欢迎直接 PR
|
||||
到 pro 的仓库
|
||||
@@ -0,0 +1,19 @@
|
||||
代码生成
|
||||
====
|
||||
|
||||
## 需求
|
||||
|
||||
> 因代码生成由后端实现,所以若需要使用代码生成功能来生成前端代码的话,需要以下修改。
|
||||
|
||||
## 实现方案
|
||||
|
||||
1. 将本目录下`antdv`文件夹放入`RuoYi-Vue`中代码生成模块(ruoyi-generator)中`resource`的`vm`文件夹下;
|
||||
|
||||
2. 将本目录中`VelocityUtils.java`文件替换掉代码生成模块中`com.ruoyi.generator.util`的
|
||||
`VelocityUtils.java`文件;
|
||||
|
||||
3. 重启后台项目,代码生成即由`element-ui`成功改为`ant design vue`。
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -0,0 +1,348 @@
|
||||
package com.ruoyi.generator.util;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.ruoyi.common.constant.GenConstants;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.generator.domain.GenTable;
|
||||
import com.ruoyi.generator.domain.GenTableColumn;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
|
||||
/**
|
||||
* 模板处理工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class VelocityUtils {
|
||||
/** 项目空间路径 */
|
||||
private static final String PROJECT_PATH = "main/java";
|
||||
|
||||
/** mybatis空间路径 */
|
||||
private static final String MYBATIS_PATH = "main/resources/mapper";
|
||||
|
||||
/** 默认上级菜单,系统工具 */
|
||||
private static final String DEFAULT_PARENT_MENU_ID = "3";
|
||||
|
||||
/**
|
||||
* 设置模板变量信息
|
||||
*
|
||||
* @return 模板列表
|
||||
*/
|
||||
public static VelocityContext prepareContext(GenTable genTable) {
|
||||
String moduleName = genTable.getModuleName();
|
||||
String businessName = genTable.getBusinessName();
|
||||
String packageName = genTable.getPackageName();
|
||||
String tplCategory = genTable.getTplCategory();
|
||||
String functionName = genTable.getFunctionName();
|
||||
|
||||
VelocityContext velocityContext = new VelocityContext();
|
||||
velocityContext.put("tplCategory", genTable.getTplCategory());
|
||||
velocityContext.put("tableName", genTable.getTableName());
|
||||
velocityContext.put(
|
||||
"functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
|
||||
velocityContext.put("ClassName", genTable.getClassName());
|
||||
velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
|
||||
velocityContext.put("moduleName", genTable.getModuleName());
|
||||
velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
|
||||
velocityContext.put("businessName", genTable.getBusinessName());
|
||||
velocityContext.put("basePackage", getPackagePrefix(packageName));
|
||||
velocityContext.put("packageName", packageName);
|
||||
velocityContext.put("author", genTable.getFunctionAuthor());
|
||||
velocityContext.put("datetime", DateUtils.getDate());
|
||||
velocityContext.put("pkColumn", genTable.getPkColumn());
|
||||
velocityContext.put("importList", getImportList(genTable));
|
||||
velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
|
||||
velocityContext.put("columns", genTable.getColumns());
|
||||
velocityContext.put("table", genTable);
|
||||
velocityContext.put("dicts", getDicts(genTable));
|
||||
setMenuVelocityContext(velocityContext, genTable);
|
||||
if (GenConstants.TPL_TREE.equals(tplCategory)) {
|
||||
setTreeVelocityContext(velocityContext, genTable);
|
||||
}
|
||||
if (GenConstants.TPL_SUB.equals(tplCategory)) {
|
||||
setSubVelocityContext(velocityContext, genTable);
|
||||
}
|
||||
return velocityContext;
|
||||
}
|
||||
|
||||
public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) {
|
||||
String options = genTable.getOptions();
|
||||
JSONObject paramsObj = JSONObject.parseObject(options);
|
||||
String parentMenuId = getParentMenuId(paramsObj);
|
||||
context.put("parentMenuId", parentMenuId);
|
||||
}
|
||||
|
||||
public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) {
|
||||
String options = genTable.getOptions();
|
||||
JSONObject paramsObj = JSONObject.parseObject(options);
|
||||
String treeCode = getTreecode(paramsObj);
|
||||
String treeParentCode = getTreeParentCode(paramsObj);
|
||||
String treeName = getTreeName(paramsObj);
|
||||
|
||||
context.put("treeCode", treeCode);
|
||||
context.put("treeParentCode", treeParentCode);
|
||||
context.put("treeName", treeName);
|
||||
context.put("expandColumn", getExpandColumn(genTable));
|
||||
if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
|
||||
context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE));
|
||||
}
|
||||
if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
|
||||
context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
public static void setSubVelocityContext(VelocityContext context, GenTable genTable) {
|
||||
GenTable subTable = genTable.getSubTable();
|
||||
String subTableName = genTable.getSubTableName();
|
||||
String subTableFkName = genTable.getSubTableFkName();
|
||||
String subClassName = genTable.getSubTable().getClassName();
|
||||
String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
|
||||
|
||||
context.put("subTable", subTable);
|
||||
context.put("subTableName", subTableName);
|
||||
context.put("subTableFkName", subTableFkName);
|
||||
context.put("subTableFkClassName", subTableFkClassName);
|
||||
context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
|
||||
context.put("subClassName", subClassName);
|
||||
context.put("subclassName", StringUtils.uncapitalize(subClassName));
|
||||
context.put("subImportList", getImportList(genTable.getSubTable()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板信息
|
||||
*
|
||||
* @return 模板列表
|
||||
*/
|
||||
public static List<String> getTemplateList(String tplCategory) {
|
||||
List<String> templates = new ArrayList<String>();
|
||||
templates.add("vm/java/domain.java.vm");
|
||||
templates.add("vm/java/mapper.java.vm");
|
||||
templates.add("vm/java/service.java.vm");
|
||||
templates.add("vm/java/serviceImpl.java.vm");
|
||||
templates.add("vm/java/controller.java.vm");
|
||||
templates.add("vm/xml/mapper.xml.vm");
|
||||
templates.add("vm/sql/sql.vm");
|
||||
templates.add("vm/antdv/js/api.js.vm");
|
||||
if (GenConstants.TPL_CRUD.equals(tplCategory) || GenConstants.TPL_TREE.equals(tplCategory)) {
|
||||
templates.add("vm/antdv/index.vue.vm");
|
||||
templates.add("vm/antdv/modules/CreateForm.vue.vm");
|
||||
} else if (GenConstants.TPL_SUB.equals(tplCategory)) {
|
||||
templates.add("vm/antdv/index.vue.vm");
|
||||
templates.add("vm/antdv/modules/CreateForm.vue.vm");
|
||||
templates.add("vm/antdv/modules/SubTable.vue.vm");
|
||||
templates.add("vm/antdv/modules/CreateSubForm.vue.vm");
|
||||
templates.add("vm/java/sub-domain.java.vm");
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
/** 获取文件名 */
|
||||
public static String getFileName(String template, GenTable genTable) {
|
||||
// 文件名称
|
||||
String fileName = "";
|
||||
// 包路径
|
||||
String packageName = genTable.getPackageName();
|
||||
// 模块名
|
||||
String moduleName = genTable.getModuleName();
|
||||
// 大写类名
|
||||
String className = genTable.getClassName();
|
||||
// 业务名称
|
||||
String businessName = genTable.getBusinessName();
|
||||
|
||||
String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
|
||||
String mybatisPath = MYBATIS_PATH + "/" + moduleName;
|
||||
String vuePath = "vue";
|
||||
|
||||
if (template.contains("domain.java.vm")) {
|
||||
fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
|
||||
}
|
||||
if (template.contains("sub-domain.java.vm")
|
||||
&& StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory())) {
|
||||
fileName =
|
||||
StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
|
||||
} else if (template.contains("mapper.java.vm")) {
|
||||
fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
|
||||
} else if (template.contains("service.java.vm")) {
|
||||
fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
|
||||
} else if (template.contains("serviceImpl.java.vm")) {
|
||||
fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
|
||||
} else if (template.contains("controller.java.vm")) {
|
||||
fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
|
||||
} else if (template.contains("mapper.xml.vm")) {
|
||||
fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
|
||||
} else if (template.contains("sql.vm")) {
|
||||
fileName = businessName + "Menu.sql";
|
||||
} else if (template.contains("api.js.vm")) {
|
||||
fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("index.vue.vm")) {
|
||||
fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("CreateForm.vue.vm")) {
|
||||
fileName =
|
||||
StringUtils.format(
|
||||
"{}/views/{}/{}/modules/CreateForm.vue", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("index-tree.vue.vm")) {
|
||||
fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("SubTable.vue.vm")) {
|
||||
fileName =
|
||||
StringUtils.format(
|
||||
"{}/views/{}/{}/modules/SubTable.vue", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("CreateSubForm.vue.vm")) {
|
||||
fileName =
|
||||
StringUtils.format(
|
||||
"{}/views/{}/{}/modules/CreateSubForm.vue", vuePath, moduleName, businessName);
|
||||
}
|
||||
System.out.println(fileName);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包前缀
|
||||
*
|
||||
* @param packageName 包名称
|
||||
* @return 包前缀名称
|
||||
*/
|
||||
public static String getPackagePrefix(String packageName) {
|
||||
int lastIndex = packageName.lastIndexOf(".");
|
||||
String basePackage = StringUtils.substring(packageName, 0, lastIndex);
|
||||
return basePackage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据列类型获取导入包
|
||||
*
|
||||
* @param genTable 业务表对象
|
||||
* @return 返回需要导入的包列表
|
||||
*/
|
||||
public static HashSet<String> getImportList(GenTable genTable) {
|
||||
List<GenTableColumn> columns = genTable.getColumns();
|
||||
GenTable subGenTable = genTable.getSubTable();
|
||||
HashSet<String> importList = new HashSet<String>();
|
||||
if (StringUtils.isNotNull(subGenTable)) {
|
||||
importList.add("java.util.List");
|
||||
}
|
||||
for (GenTableColumn column : columns) {
|
||||
if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) {
|
||||
importList.add("java.util.Date");
|
||||
importList.add("com.fasterxml.jackson.annotation.JsonFormat");
|
||||
} else if (!column.isSuperColumn()
|
||||
&& GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
|
||||
importList.add("java.math.BigDecimal");
|
||||
}
|
||||
}
|
||||
return importList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据列类型获取字典组
|
||||
*
|
||||
* @param genTable 业务表对象
|
||||
* @return 返回字典组
|
||||
*/
|
||||
public static String getDicts(GenTable genTable) {
|
||||
List<GenTableColumn> columns = genTable.getColumns();
|
||||
List<String> dicts = new ArrayList<String>();
|
||||
for (GenTableColumn column : columns) {
|
||||
if (!column.isSuperColumn()
|
||||
&& StringUtils.isNotEmpty(column.getDictType())
|
||||
&& StringUtils.equalsAny(
|
||||
column.getHtmlType(),
|
||||
new String[] {
|
||||
GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX
|
||||
})) {
|
||||
dicts.add("'" + column.getDictType() + "'");
|
||||
}
|
||||
}
|
||||
return StringUtils.join(dicts, ", ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限前缀
|
||||
*
|
||||
* @param moduleName 模块名称
|
||||
* @param businessName 业务名称
|
||||
* @return 返回权限前缀
|
||||
*/
|
||||
public static String getPermissionPrefix(String moduleName, String businessName) {
|
||||
return StringUtils.format("{}:{}", moduleName, businessName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上级菜单ID字段
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 上级菜单ID字段
|
||||
*/
|
||||
public static String getParentMenuId(JSONObject paramsObj) {
|
||||
if (StringUtils.isNotEmpty(paramsObj)
|
||||
&& paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
|
||||
&& StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID))) {
|
||||
return paramsObj.getString(GenConstants.PARENT_MENU_ID);
|
||||
}
|
||||
return DEFAULT_PARENT_MENU_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树编码
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 树编码
|
||||
*/
|
||||
public static String getTreecode(JSONObject paramsObj) {
|
||||
if (paramsObj.containsKey(GenConstants.TREE_CODE)) {
|
||||
return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树父编码
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 树父编码
|
||||
*/
|
||||
public static String getTreeParentCode(JSONObject paramsObj) {
|
||||
if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
|
||||
return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树名称
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 树名称
|
||||
*/
|
||||
public static String getTreeName(JSONObject paramsObj) {
|
||||
if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
|
||||
return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需要在哪一列上面显示展开按钮
|
||||
*
|
||||
* @param genTable 业务表对象
|
||||
* @return 展开按钮列序号
|
||||
*/
|
||||
public static int getExpandColumn(GenTable genTable) {
|
||||
String options = genTable.getOptions();
|
||||
JSONObject paramsObj = JSONObject.parseObject(options);
|
||||
String treeName = paramsObj.getString(GenConstants.TREE_NAME);
|
||||
int num = 0;
|
||||
for (GenTableColumn column : genTable.getColumns()) {
|
||||
if (column.isList()) {
|
||||
num++;
|
||||
String columnName = column.getColumnName();
|
||||
if (columnName.equals(treeName)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
<template>
|
||||
<page-header-wrapper>
|
||||
<a-card :bordered="false">
|
||||
<!-- 条件搜索 -->
|
||||
<div class="table-page-search-wrapper">
|
||||
<a-form layout="inline">
|
||||
<a-row :gutter="48">
|
||||
#set($isInsert=0)
|
||||
#set($isEdit=0)
|
||||
#set($queryCount=0)
|
||||
#set($querySpace="")
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert)
|
||||
#set($isInsert=1)
|
||||
#end
|
||||
#if($column.edit)
|
||||
#set($isEdit=1)
|
||||
#end
|
||||
#if($column.query)
|
||||
#set($queryCount=$queryCount+1)
|
||||
#set($dictType=$column.dictType)
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($queryCount == 3)
|
||||
<template v-if="advanced">
|
||||
#set($querySpace=" ")
|
||||
#end
|
||||
#if($column.htmlType == "input")
|
||||
${querySpace}
|
||||
<a-col :md="8" :sm="24">
|
||||
${querySpace}
|
||||
<a-form-item label="${comment}" prop="${column.javaField}">
|
||||
${querySpace}
|
||||
<a-input v-model="queryParam.${column.javaField}"
|
||||
placeholder="请输入${comment}" allow-clear/>
|
||||
${querySpace}</a-form-item>
|
||||
${querySpace}</a-col>
|
||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") &&
|
||||
"" != $dictType)
|
||||
${querySpace}
|
||||
<a-col :md="8" :sm="24">
|
||||
${querySpace}
|
||||
<a-form-item label="${comment}" prop="${column.javaField}">
|
||||
${querySpace}
|
||||
<a-select placeholder="请选择${comment}"
|
||||
v-model="queryParam.${column.javaField}" style="width: 100%"
|
||||
allow-clear>
|
||||
${querySpace}
|
||||
<a-select-option v-for="(d, index) in ${column.javaField}Options"
|
||||
:key="index" :value="d.dictValue">{{ d.dictLabel }}
|
||||
</a-select-option>
|
||||
${querySpace}</a-select>
|
||||
${querySpace}</a-form-item>
|
||||
${querySpace}</a-col>
|
||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
|
||||
${querySpace}
|
||||
<a-col :md="8" :sm="24">
|
||||
${querySpace}
|
||||
<a-form-item label="${comment}" prop="${column.javaField}">
|
||||
${querySpace}
|
||||
<a-select placeholder="请选择${comment}"
|
||||
v-model="queryParam.${column.javaField}" style="width: 100%"
|
||||
allow-clear>
|
||||
${querySpace}
|
||||
<a-select-option>请选择字典生成</a-select-option>
|
||||
${querySpace}</a-select>
|
||||
${querySpace}</a-form-item>
|
||||
${querySpace}</a-col>
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
|
||||
${querySpace}
|
||||
<a-col :md="8" :sm="24">
|
||||
${querySpace}
|
||||
<a-form-item label="${comment}" prop="${column.javaField}">
|
||||
${querySpace}
|
||||
<a-date-picker style="width: 100%" v-model="queryParam.${column.javaField}"
|
||||
format="YYYY-MM-DD HH:mm:ss" allow-clear/>
|
||||
${querySpace}</a-form-item>
|
||||
${querySpace}</a-col>
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
${querySpace}
|
||||
<a-col :md="8" :sm="24">
|
||||
${querySpace}
|
||||
<a-form-item label="${comment}">
|
||||
${querySpace}
|
||||
<a-range-picker style="width: 100%" v-model="daterange${AttrName}"
|
||||
valueFormat="YYYY-MM-DD" format="YYYY-MM-DD" allow-clear/>
|
||||
${querySpace}</a-form-item>
|
||||
${querySpace}</a-col>
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#if($queryCount > 2)
|
||||
</template>
|
||||
#end
|
||||
<a-col :md="!advanced && 8 || 24" :sm="24">
|
||||
<span class="table-page-search-submitButtons"
|
||||
:style="advanced && { float: 'right', overflow: 'hidden' } || {} ">
|
||||
<a-button type="primary" @click="handleQuery"><a-icon type="search"/>查询</a-button>
|
||||
<a-button style="margin-left: 8px" @click="resetQuery"><iot-icon
|
||||
type="icon-refresh"/>重置</a-button>
|
||||
#if($queryCount > 2)
|
||||
<a @click="toggleAdvanced" style="margin-left: 8px">
|
||||
{{ advanced ? '收起' : '展开' }}
|
||||
<a-icon :type="advanced ? 'up' : 'down'"/>
|
||||
</a>
|
||||
#end
|
||||
</span>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</div>
|
||||
<!-- 操作 -->
|
||||
<div class="table-operations">
|
||||
#if($isInsert == 1)
|
||||
<a-button type="primary" @click="$refs.createForm.handleAdd()"
|
||||
v-hasPermi="['${moduleName}:${businessName}:add']">
|
||||
<a-icon type="plus"/>
|
||||
新增
|
||||
</a-button>
|
||||
#end
|
||||
#if($isEdit == 1)
|
||||
<a-button type="primary" :disabled="single"
|
||||
@click="$refs.createForm.handleUpdate(undefined, ids)"
|
||||
v-hasPermi="['${moduleName}:${businessName}:edit']">
|
||||
<iot-icon type="icon-u-edit"/>
|
||||
修改
|
||||
</a-button>
|
||||
#end
|
||||
<a-button type="danger" :disabled="multiple" @click="handleDelete"
|
||||
v-hasPermi="['${moduleName}:${businessName}:remove']">
|
||||
<a-icon type="delete"/>
|
||||
删除
|
||||
</a-button>
|
||||
<a-button type="primary" @click="handleExport"
|
||||
v-hasPermi="['${moduleName}:${businessName}:export']">
|
||||
<iot-icon type="icon-u-export"/>
|
||||
导出
|
||||
</a-button>
|
||||
<a-button
|
||||
type="dashed"
|
||||
shape="circle"
|
||||
:loading="loading"
|
||||
:style="{float: 'right'}"
|
||||
icon="reload"
|
||||
@click="getList"/>
|
||||
</div>
|
||||
#if($isInsert == 1 || $isEdit == 1)
|
||||
<!-- 增加修改 -->
|
||||
<create-form
|
||||
ref="createForm"
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
:${column.javaField}Options="${column.javaField}Options"
|
||||
#end
|
||||
#end
|
||||
#if($tplCategory == 'tree')
|
||||
:${businessName}Options="${businessName}Options"
|
||||
@select-tree="getTreeselect"
|
||||
#end
|
||||
@ok="getList"
|
||||
/>
|
||||
#end
|
||||
<!-- 数据展示 -->
|
||||
<a-table
|
||||
:loading="loading"
|
||||
:size="tableSize"
|
||||
rowKey="${pkColumn.javaField}"
|
||||
:columns="columns"
|
||||
:data-source="list"
|
||||
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
|
||||
:pagination="false">
|
||||
#foreach($column in $columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.list && $column.htmlType == "datetime")
|
||||
<span slot="${javaField}" slot-scope="text, record">
|
||||
{{ parseTime(record.${javaField}) }}
|
||||
</span>
|
||||
#elseif($column.list && "" != $column.dictType)
|
||||
<span slot="${javaField}" slot-scope="text, record">
|
||||
{{ ${javaField}Format(record) }}
|
||||
</span>
|
||||
#end
|
||||
#end
|
||||
<span slot="operation" slot-scope="text, record">
|
||||
#if($isEdit == 1)
|
||||
<a-divider type="vertical" v-hasPermi="['${moduleName}:${businessName}:edit']"/>
|
||||
<a @click="$refs.createForm.handleUpdate(record, undefined)"
|
||||
v-hasPermi="['${moduleName}:${businessName}:edit']">
|
||||
<iot-icon type="icon-u-edit"/>修改
|
||||
</a>
|
||||
#end
|
||||
#if($tplCategory == 'tree' && ($isInsert == 1 || $isEdit == 1))
|
||||
<a-divider type="vertical" v-hasPermi="['${moduleName}:${businessName}:add']"/>
|
||||
<a @click="$refs.createForm.handleAdd(record)"
|
||||
v-hasPermi="['${moduleName}:${businessName}:add']">
|
||||
<a-icon type="plus"/>新增
|
||||
</a>
|
||||
#end
|
||||
<a-divider type="vertical" v-hasPermi="['${moduleName}:${businessName}:remove']"/>
|
||||
<a @click="handleDelete(record)" v-hasPermi="['${moduleName}:${businessName}:remove']">
|
||||
<a-icon type="delete"/>删除
|
||||
</a>
|
||||
</span>
|
||||
</a-table>
|
||||
#if($tplCategory != 'tree')
|
||||
<!-- 分页 -->
|
||||
<a-pagination
|
||||
class="ant-table-pagination"
|
||||
show-size-changer
|
||||
show-quick-jumper
|
||||
:current="queryParam.pageNum"
|
||||
:total="total"
|
||||
:page-size="queryParam.pageSize"
|
||||
:showTotal="total => `共 ${total} 条`"
|
||||
@showSizeChange="onShowSizeChange"
|
||||
@change="changeSize"
|
||||
/>
|
||||
#end
|
||||
</a-card>
|
||||
</page-header-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {del${BusinessName}, list${BusinessName}} from '@/api/'
|
||||
import CreateForm from './modules/CreateForm'
|
||||
|
||||
export default {
|
||||
name: '${BusinessName}',
|
||||
components: {
|
||||
#if($isInsert == 1 || $isEdit == 1)
|
||||
CreateForm
|
||||
#end
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
selectedRowKeys: [],
|
||||
selectedRows: [],
|
||||
// 高级搜索 展开/关闭
|
||||
advanced: false,
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
ids: [],
|
||||
loading: false,
|
||||
total: 0,
|
||||
#if($tplCategory == 'tree' && ($isInsert == 1 || $isEdit == 1))
|
||||
${businessName}Options: [],
|
||||
#end
|
||||
#foreach ($column in $columns)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if(${column.dictType} != '')
|
||||
// $comment字典
|
||||
${column.javaField}Options: [],
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
// $comment时间范围
|
||||
daterange${AttrName}: [],
|
||||
#end
|
||||
#end
|
||||
// 查询参数
|
||||
queryParam: {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.query)
|
||||
$column.javaField: null,
|
||||
#end
|
||||
#end
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
columns: [
|
||||
#foreach($column in $columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.pk)
|
||||
{
|
||||
title: '${comment}',
|
||||
dataIndex: '${javaField}',
|
||||
ellipsis: true,
|
||||
align: 'center'
|
||||
},
|
||||
#elseif($column.list && $column.htmlType == "datetime" || $column.list &&
|
||||
"" != $column.dictType || $column.list && "" != $column.dictType)
|
||||
{
|
||||
title: '${comment}',
|
||||
dataIndex: '${javaField}',
|
||||
scopedSlots: {customRender: '${javaField}'},
|
||||
ellipsis: true,
|
||||
align: 'center'
|
||||
},
|
||||
#elseif($column.list && "" != $javaField)
|
||||
{
|
||||
title: '${comment}',
|
||||
dataIndex: '${javaField}',
|
||||
ellipsis: true,
|
||||
align: 'center'
|
||||
},
|
||||
#end
|
||||
#end
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: '18%',
|
||||
scopedSlots: {customRender: 'operation'},
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {
|
||||
this.getList()
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
this.getDicts('${column.dictType}').then(response => {
|
||||
this.${column.javaField}Options = response.data
|
||||
})
|
||||
#end
|
||||
#end
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
methods: {
|
||||
/** 查询${functionName}列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
this.queryParam.params = {}
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
if (this.daterange${AttrName} !== null && this.daterange${AttrName} !== ''
|
||||
&& this.daterange${AttrName}.length !== 0) {
|
||||
this.queryParam.params['begin${AttrName}'] = this.daterange${AttrName}[0]
|
||||
this.queryParam.params['end${AttrName}'] = this.daterange${AttrName}[1]
|
||||
}
|
||||
#end
|
||||
#end
|
||||
list${BusinessName}(this.queryParam).then(response => {
|
||||
#if($tplCategory == 'tree' && ($isInsert == 1 || $isEdit == 1))
|
||||
this.list = this.handleTree(response.data, '${treeCode}', '${treeParentCode}')
|
||||
#else
|
||||
this.list = response.rows
|
||||
#end
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
// $comment字典翻译
|
||||
${column.javaField}Format(row, column) {
|
||||
#if($column.htmlType == "checkbox")
|
||||
if (row.${column.javaField} === null || row.${column.javaField} === undefined) {
|
||||
return null
|
||||
}
|
||||
#end
|
||||
return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(
|
||||
this.${column.javaField}Options, row.${column.javaField})
|
||||
},
|
||||
#end
|
||||
#end
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParam.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
this.daterange${AttrName} = []
|
||||
#end
|
||||
#end
|
||||
this.queryParam = {
|
||||
#foreach($column in $columns)
|
||||
#if($column.query)
|
||||
#set($dictType=$column.dictType)
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if(!($column.htmlType == "datetime" && $column.queryType == "BETWEEN"))
|
||||
${column.javaField}: undefined,
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
this.handleQuery()
|
||||
},
|
||||
onShowSizeChange(current, pageSize) {
|
||||
this.queryParam.pageSize = pageSize
|
||||
this.getList()
|
||||
},
|
||||
changeSize(current, pageSize) {
|
||||
this.queryParam.pageNum = current
|
||||
this.queryParam.pageSize = pageSize
|
||||
this.getList()
|
||||
},
|
||||
onSelectChange(selectedRowKeys, selectedRows) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
this.selectedRows = selectedRows
|
||||
this.ids = this.selectedRows.map(item => item.${pkColumn.javaField})
|
||||
this.single = selectedRowKeys.length !== 1
|
||||
this.multiple = !selectedRowKeys.length
|
||||
},
|
||||
toggleAdvanced() {
|
||||
this.advanced = !this.advanced
|
||||
},
|
||||
#if($tplCategory == 'tree' && ($isInsert == 1 || $isEdit == 1))
|
||||
/** 查询菜单下拉树结构 */
|
||||
getTreeselect() {
|
||||
list${BusinessName}().then(response => {
|
||||
this.${businessName}Options = []
|
||||
const data = {${treeCode}: 0, ${treeName}: '主目录', children: []}
|
||||
data.children = this.handleTree(response.data, '${treeCode}', '${treeParentCode}')
|
||||
this.${businessName}Options.push(data)
|
||||
})
|
||||
},
|
||||
#end
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
var that = this
|
||||
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids
|
||||
this.$confirm({
|
||||
title: '确认删除所选中数据?',
|
||||
content: '当前选中编号为' + ${pkColumn.javaField}s + '的数据',
|
||||
onOk() {
|
||||
return del${BusinessName}(${pkColumn.javaField}s)
|
||||
.then(() => {
|
||||
that.onSelectChange([], [])
|
||||
that.getList()
|
||||
that.$message.success(
|
||||
'删除成功',
|
||||
3
|
||||
)
|
||||
})
|
||||
},
|
||||
onCancel() {
|
||||
}
|
||||
})
|
||||
},
|
||||
/** 导出按钮操作 */
|
||||
handleExport() {
|
||||
var that = this
|
||||
this.$confirm({
|
||||
title: '是否确认导出?',
|
||||
content: '此操作将导出当前条件下所有数据而非选中数据',
|
||||
onOk() {
|
||||
that.download('${moduleName}/${businessName}/export', {
|
||||
...that.queryParam
|
||||
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
|
||||
},
|
||||
onCancel() {
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,44 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询${functionName}列表
|
||||
export function list${BusinessName} (query) {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询${functionName}详细
|
||||
export function get${BusinessName} (${pkColumn.javaField}) {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增${functionName}
|
||||
export function add${BusinessName} (data) {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改${functionName}
|
||||
export function update${BusinessName} (data) {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除${functionName}
|
||||
export function del${BusinessName} (${pkColumn.javaField}) {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
#set($isInsert=0)
|
||||
#set($isEdit=0)
|
||||
#set($hasRichText=0)
|
||||
#foreach($column in $columns)
|
||||
#if($column.insert)
|
||||
#set($isInsert=1)
|
||||
#end
|
||||
#if($column.edit)
|
||||
#set($isEdit=1)
|
||||
#end
|
||||
#if($isInsert == 1 && $isEdit == 1)
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#if($isInsert == 0 && $isEdit == 0)
|
||||
<template>
|
||||
<a-result title="多余文件,请删除">
|
||||
<template #icon>
|
||||
<a-icon type="smile" theme="twoTone"/>
|
||||
</template>
|
||||
<template #extra>
|
||||
<a-button type="primary" @click="returnIndex">
|
||||
返回首页
|
||||
</a-button>
|
||||
</template>
|
||||
</a-result>
|
||||
</template>
|
||||
|
||||
#stop
|
||||
#end
|
||||
<template>
|
||||
<a-drawer width="35%" :label-col="4" :wrapper-col="14" :visible="open" @close="onClose">
|
||||
<a-divider orientation="left">
|
||||
<b>{{ formTitle }}</b>
|
||||
</a-divider>
|
||||
<a-form-model ref="form" :model="form" :rules="rules">
|
||||
#set($requiredCount = 0)
|
||||
#set($ruleLastIndex = 0)
|
||||
#foreach($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
#set($ruleLastIndex = $foreach.count)
|
||||
#end
|
||||
#set($field=$column.javaField)
|
||||
#if(($column.insert || $column.edit) && !$column.pk)
|
||||
#if(($column.usableColumn) || (!$column.superColumn))
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.required)
|
||||
#set($requiredCount = $requiredCount + 1)
|
||||
#end
|
||||
#set($dictType=$column.dictType)
|
||||
<a-form-model-item label="${comment}" prop="${field}"
|
||||
#if($column.insert && !$column.edit)v-if="formType === 1"#end#if(!$column.insert && $column.edit)v-if="formType === 2"#end>
|
||||
#if("" != $treeParentCode && $column.javaField == $treeParentCode)
|
||||
<a-tree-select
|
||||
v-model="form.${field}"
|
||||
style="width: 100%"
|
||||
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
|
||||
:tree-data="${businessName}Options"
|
||||
placeholder="请选择"
|
||||
:replaceFields="{children:'children', title:'${treeName}', key:'${treeCode}', value: '${treeCode}' }"
|
||||
tree-default-expand-all
|
||||
>
|
||||
</a-tree-select>
|
||||
#elseif($column.htmlType == "input")
|
||||
<a-input v-model="form.${field}" placeholder="请输入${comment}"/>
|
||||
#elseif($column.htmlType == "imageUpload")
|
||||
<file-upload v-model="form.${field}" type="image"></file-upload>
|
||||
#elseif($column.htmlType == "fileUpload")
|
||||
<file-upload v-model="form.${field}" type="file"></file-upload>
|
||||
#elseif($column.htmlType == "editor")
|
||||
#set($hasRichText=1)
|
||||
<editor ref="${field}Editor" v-model="form.${field}"/>
|
||||
#elseif($column.htmlType == "select" && "" != $dictType)
|
||||
<a-select placeholder="请选择${comment}" v-model="form.${field}">
|
||||
<a-select-option v-for="(d, index) in ${field}Options" :key="index"
|
||||
:value="d.dictValue">{{ d.dictLabel }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
#elseif($column.htmlType == "select" && $dictType)
|
||||
<a-select placeholder="请选择${comment}" v-model="form.${field}">
|
||||
<a-select-option value="">请选择字典生成</a-select-option>
|
||||
</a-select>
|
||||
#elseif($column.htmlType == "checkbox" && "" != $dictType)
|
||||
<a-select
|
||||
mode="multiple"
|
||||
v-model="form.${field}"
|
||||
placeholder="请选择${comment}"
|
||||
>
|
||||
<a-select-option v-for="(d, index) in ${field}Options" :key="index"
|
||||
:value="d.dictValue">{{ d.dictLabel }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
#elseif($column.htmlType == "checkbox" && $dictType)
|
||||
<a-select placeholder="请选择${comment}" v-model="form.${field}">
|
||||
<a-select-option value="">请选择字典生成</a-select-option>
|
||||
</a-select>
|
||||
#elseif($column.htmlType == "radio" && "" != $dictType)
|
||||
<a-radio-group v-model="form.${field}" button-style="solid">
|
||||
<a-radio-button v-for="(d, index) in ${field}Options" :key="index"
|
||||
:value="d.dictValue">{{ d.dictLabel }}
|
||||
</a-radio-button>
|
||||
</a-radio-group>
|
||||
#elseif($column.htmlType == "radio" && $dictType)
|
||||
<a-radio-group v-model="form.${field}" button-style="solid">
|
||||
<a-radio-button value="">请选择字典生成</a-radio-button>
|
||||
</a-radio-group>
|
||||
#elseif($column.htmlType == "datetime")
|
||||
<a-date-picker style="width: 100%" v-model="form.${field}"
|
||||
format="YYYY-MM-DD HH:mm:ss" allow-clear/>
|
||||
#elseif($column.htmlType == "textarea")
|
||||
<a-input v-model="form.${field}" placeholder="请输入内容" type="textarea"
|
||||
allow-clear/>
|
||||
#end
|
||||
</a-form-model-item>
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#if($table.sub)
|
||||
<a-divider orientation="left">
|
||||
<b>${subTable.functionName}</b>
|
||||
</a-divider>
|
||||
<sub-table ref="subTable" :list="subList" @add="handleAdd${subclassName}"
|
||||
@delete="handleDelete${subclassName}"/>
|
||||
<p>当前存在 {{ subList.length }} 条信息</p>
|
||||
<a-button type="dashed" @click="$refs.subTable.show()">
|
||||
详情
|
||||
</a-button>
|
||||
<br>
|
||||
#end
|
||||
<div class="bottom-control">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="submitForm">
|
||||
保存
|
||||
</a-button>
|
||||
<a-button type="dashed" @click="cancel">
|
||||
取消
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</a-form-model>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {add${BusinessName}, get${BusinessName}, update${BusinessName}} from '@/api/'
|
||||
import SubTable from './SubTable'
|
||||
import Editor from '@/components/Editor'
|
||||
#if($table.sub)
|
||||
#end
|
||||
#if($hasRichText == 1)
|
||||
#end
|
||||
|
||||
export default {
|
||||
name: 'CreateForm',
|
||||
props: {
|
||||
#set($propsCount = 0)
|
||||
#foreach ($column in $columns)
|
||||
#if(${column.dictType} != '')
|
||||
#set($propsCount = 1)
|
||||
${column.javaField}Options: {
|
||||
type: Array,
|
||||
required: true
|
||||
#if($foreach.count!=$ruleLastIndex || $tplCategory == 'tree')
|
||||
},
|
||||
#else
|
||||
}
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#if($tplCategory == 'tree')
|
||||
${businessName}Options: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
#end
|
||||
}
|
||||
,
|
||||
components: {
|
||||
#if($table.sub)
|
||||
SubTable#if($hasRichText == 1),#end
|
||||
#end
|
||||
#if($hasRichText == 1)
|
||||
Editor
|
||||
#end
|
||||
}
|
||||
,
|
||||
data()
|
||||
{
|
||||
return {
|
||||
loading: false,
|
||||
#if($table.sub)
|
||||
subList: [],
|
||||
#end
|
||||
formTitle: '',
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.htmlType == "editor")
|
||||
${column.javaField}Editor: '',
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
// 表单参数
|
||||
form: {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.htmlType == "radio")
|
||||
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0
|
||||
#else'0'#end#if($foreach.count != $columns.size()),#end
|
||||
#elseif($column.htmlType == "checkbox")
|
||||
$column.javaField: []#if($foreach.count != $columns.size()),#end
|
||||
#else
|
||||
$column.javaField: null#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
|
||||
#end
|
||||
#end
|
||||
},
|
||||
// 1增加,2修改
|
||||
formType: 1,
|
||||
open: false,
|
||||
rules: {
|
||||
#set($currentRequiredCount = 1)
|
||||
#foreach ($column in $columns)
|
||||
#if(($column.insert || $column.edit) && !$column.pk)
|
||||
#if(($column.usableColumn) || (!$column.superColumn))
|
||||
#if($column.required)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
$column.javaField: [
|
||||
{
|
||||
required: true, message: '$comment不能为空', trigger: #if($column.htmlType ==
|
||||
"select")'change'#else'blur'#end }
|
||||
]#if($currentRequiredCount != $requiredCount),#end
|
||||
|
||||
#set($currentRequiredCount = $currentRequiredCount + 1)
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
}
|
||||
}
|
||||
,
|
||||
filters: {
|
||||
}
|
||||
,
|
||||
created()
|
||||
{
|
||||
}
|
||||
,
|
||||
computed: {
|
||||
}
|
||||
,
|
||||
watch: {
|
||||
}
|
||||
,
|
||||
mounted()
|
||||
{
|
||||
}
|
||||
,
|
||||
methods: {
|
||||
onClose()
|
||||
{
|
||||
this.open = false
|
||||
#if($table.sub)
|
||||
this.subList = []
|
||||
#end
|
||||
}
|
||||
,
|
||||
// 取消按钮
|
||||
cancel()
|
||||
{
|
||||
this.open = false
|
||||
this.reset()
|
||||
#if($table.sub)
|
||||
this.subList = []
|
||||
#end
|
||||
}
|
||||
,
|
||||
// 表单重置
|
||||
reset()
|
||||
{
|
||||
this.formType = 1
|
||||
this.form = {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.htmlType == "radio")
|
||||
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0
|
||||
#else'0'#end#if($foreach.count != $columns.size()),#end
|
||||
#elseif($column.htmlType == "checkbox")
|
||||
$column.javaField: []#if($foreach.count != $columns.size()),#end
|
||||
#else
|
||||
$column.javaField: null#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
|
||||
#end
|
||||
#end
|
||||
}
|
||||
}
|
||||
,
|
||||
/** 新增按钮操作 */
|
||||
handleAdd(row)
|
||||
{
|
||||
this.reset()
|
||||
#if($tplCategory == 'tree')
|
||||
this.$emit('select-tree')
|
||||
if (row != null && row.${treeCode}) {
|
||||
this.form.${treeParentCode} = row.${treeCode}
|
||||
} else {
|
||||
this.form.${treeParentCode} = 0
|
||||
}
|
||||
#end
|
||||
this.formType = 1
|
||||
this.open = true
|
||||
this.formTitle = '添加'
|
||||
}
|
||||
,
|
||||
#if($table.sub)
|
||||
/** 新增子项操作 */
|
||||
handleAdd${subclassName} (row)
|
||||
{
|
||||
this.subList.push(row)
|
||||
}
|
||||
,
|
||||
/** 删除子项操作 */
|
||||
handleDelete${subclassName} (index, indexs)
|
||||
{
|
||||
if (index !== undefined) {
|
||||
this.subList.splice(index, 1)
|
||||
return
|
||||
}
|
||||
indexs.forEach(item => {
|
||||
this.subList.splice(item, 1)
|
||||
})
|
||||
}
|
||||
,
|
||||
#end
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row, ids)
|
||||
{
|
||||
this.reset()
|
||||
#if($tplCategory == 'tree')
|
||||
this.$emit('select-tree')
|
||||
#end
|
||||
this.formType = 2
|
||||
const ${pkColumn.javaField} = row ? row.${pkColumn.javaField} : ids
|
||||
get${BusinessName}(${pkColumn.javaField}).then(response => {
|
||||
this.form = response.data
|
||||
#if($table.sub)
|
||||
this.subList = response.data.${subclassName}List
|
||||
#end
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "checkbox")
|
||||
if (this.form.$column.javaField !== null) {
|
||||
this.form.$column.javaField = this.form.${column.javaField}.split(',')
|
||||
} else {
|
||||
this.form.$column.javaField = undefined
|
||||
}
|
||||
#end
|
||||
#end
|
||||
this.open = true
|
||||
this.formTitle = '修改'
|
||||
})
|
||||
}
|
||||
,
|
||||
/** 提交按钮 */
|
||||
submitForm: function () {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.htmlType == "editor")
|
||||
this.form.${column.javaField} = this.${column.javaField}Editor.getValue()
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
this.
|
||||
#
|
||||
[[$]]
|
||||
#refs.form.validate(valid => {
|
||||
if (valid) {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "checkbox")
|
||||
this.form.$column.javaField = this.form.${column.javaField}.join(',')
|
||||
#end
|
||||
#end
|
||||
#if($table.sub)
|
||||
this.form.${subclassName}List = this.subList
|
||||
#end
|
||||
if (this.form.${pkColumn.javaField} !== undefined && this.form.${pkColumn.javaField}
|
||||
!== null) {
|
||||
update${BusinessName}(this.form).then(response => {
|
||||
this.$message.success(
|
||||
'修改成功',
|
||||
3
|
||||
)
|
||||
this.open = false
|
||||
this.$emit('ok')
|
||||
})
|
||||
} else {
|
||||
add${BusinessName}(this.form).then(response => {
|
||||
this.$message.success(
|
||||
'新增成功',
|
||||
3
|
||||
)
|
||||
this.open = false
|
||||
this.$emit('ok')
|
||||
})
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<!-- 增加修改 -->
|
||||
<a-drawer width="35%" :label-col="4" :wrapper-col="14" :visible="open" @close="onClose">
|
||||
<a-divider orientation="left">
|
||||
<b>${subTable.functionName}</b>
|
||||
</a-divider>
|
||||
<a-form-model ref="form" :model="form">
|
||||
#set($columnLastIndex = 0)
|
||||
#foreach($column in $subTable.columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.pk || $javaField == ${subTableFkclassName})
|
||||
#elseif($column.list && "" != $javaField)
|
||||
#set($columnLastIndex = $foreach.count)
|
||||
<a-form-model-item label="${comment}" prop="${javaField}">
|
||||
<a-input v-model="form.${javaField}" placeholder="请输入"/>
|
||||
</a-form-model-item>
|
||||
#end
|
||||
#end
|
||||
<div class="bottom-control">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="submitForm">
|
||||
保存
|
||||
</a-button>
|
||||
<a-button type="dashed" @click="cancel">
|
||||
取消
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</a-form-model>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'CreateSubForm',
|
||||
props: {},
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
formTitle: '增加',
|
||||
// 表单参数
|
||||
form: {
|
||||
#foreach($column in $subTable.columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#if($column.pk || $javaField == ${subTableFkclassName})
|
||||
#elseif($column.list && "" != $javaField)
|
||||
${$javaField}: undefined#if($columnLastIndex != $foreach.count),#end
|
||||
|
||||
#end
|
||||
#end
|
||||
},
|
||||
open: false
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
methods: {
|
||||
onClose() {
|
||||
this.open = false
|
||||
},
|
||||
// 取消按钮
|
||||
cancel() {
|
||||
this.open = false
|
||||
this.reset()
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
this.form = {
|
||||
#foreach($column in $subTable.columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#if($column.pk || $javaField == ${subTableFkclassName})
|
||||
#elseif($column.list && "" != $javaField)
|
||||
${$javaField}: undefined#if($columnLastIndex != $foreach.count),#end
|
||||
|
||||
#end
|
||||
#end
|
||||
}
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.open = true
|
||||
this.reset()
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm: function () {
|
||||
this.$emit('add', this.form)
|
||||
this.open = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<a-modal
|
||||
ref="subTableModel"
|
||||
:title="'${subTable.functionName}'"
|
||||
width="80%"
|
||||
:visible="visible"
|
||||
@cancel="close"
|
||||
>
|
||||
<template slot="footer">
|
||||
<a-button type="dashed" @click="close">
|
||||
关闭
|
||||
</a-button>
|
||||
</template>
|
||||
<a-card :bordered="false">
|
||||
<!-- 操作 -->
|
||||
<div class="table-operations">
|
||||
<a-button type="primary" @click="$refs.createSubForm.handleAdd()">
|
||||
<a-icon type="plus"/>
|
||||
新增
|
||||
</a-button>
|
||||
<a-button type="danger" :disabled="multiple" @click="handleDelete">
|
||||
<a-icon type="delete"/>
|
||||
删除
|
||||
</a-button>
|
||||
</div>
|
||||
<!-- 增加修改 -->
|
||||
<create-sub-form
|
||||
ref="createSubForm"
|
||||
@add="handleAdd${subClassName}"
|
||||
/>
|
||||
<!-- 数据展示 -->
|
||||
<a-table
|
||||
:loading="loading"
|
||||
:size="tableSize"
|
||||
rowKey="${subTableFkclassName}"
|
||||
:columns="columns"
|
||||
:data-source="list"
|
||||
:row-selection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
|
||||
:pagination="false">
|
||||
<span slot="operation" slot-scope="text, record">
|
||||
<a-divider type="vertical"/>
|
||||
<a @click="handleDelete(record)">
|
||||
<a-icon type="delete"/>删除
|
||||
</a>
|
||||
</span>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CreateSubForm from './CreateSubForm'
|
||||
|
||||
export default {
|
||||
name: 'SubTable',
|
||||
components: {
|
||||
CreateSubForm
|
||||
},
|
||||
props: {
|
||||
list: {
|
||||
type: Array,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
selectedRowKeys: [],
|
||||
selectedRows: [],
|
||||
// 高级搜索 展开/关闭
|
||||
advanced: false,
|
||||
// 非单个禁用
|
||||
single: true,
|
||||
// 非多个禁用
|
||||
multiple: true,
|
||||
ids: [],
|
||||
loading: false,
|
||||
columns: [
|
||||
#foreach($column in $subTable.columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.pk || $javaField == ${subTableFkclassName})
|
||||
#elseif($column.list && "" != $javaField)
|
||||
{
|
||||
title: '${comment}',
|
||||
dataIndex: '${javaField}',
|
||||
ellipsis: true,
|
||||
align: 'center'
|
||||
},
|
||||
#end
|
||||
#end
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: '18%',
|
||||
scopedSlots: {customRender: 'operation'},
|
||||
align: 'center'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
filters: {},
|
||||
created() {
|
||||
},
|
||||
computed: {},
|
||||
watch: {},
|
||||
methods: {
|
||||
// 关闭模态框
|
||||
close() {
|
||||
this.visible = false
|
||||
this.selectedRowKeys = []
|
||||
this.selectedRows = []
|
||||
},
|
||||
// 打开抽屉(由外面的组件调用)
|
||||
show() {
|
||||
this.visible = true
|
||||
},
|
||||
onSelectChange(selectedRowKeys, selectedRows) {
|
||||
this.selectedRowKeys = selectedRowKeys
|
||||
this.selectedRows = selectedRows
|
||||
this.ids = selectedRowKeys.map(item => item - 1)
|
||||
this.single = selectedRowKeys.length !== 1
|
||||
this.multiple = !selectedRowKeys.length
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
var that = this
|
||||
if (row) {
|
||||
var index = (this.list || []).findIndex((item) => item === row)
|
||||
}
|
||||
const ids = index !== undefined ? index : this.ids
|
||||
this.$confirm({
|
||||
title: '确认删除所选中数据?',
|
||||
content: '当前选中序号为' + ids + '的数据',
|
||||
onOk() {
|
||||
that.$emit('delete', index, ids)
|
||||
},
|
||||
onCancel() {
|
||||
}
|
||||
})
|
||||
},
|
||||
handleAdd${subClassName} (row) {
|
||||
this.$emit('add', row)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,39 @@
|
||||
先增加依赖
|
||||
|
||||
```bash
|
||||
// npm
|
||||
$ npm install --save-dev webpack-bundle-analyzer
|
||||
|
||||
// or yarn
|
||||
$ yarn add webpack-bundle-analyzer -D
|
||||
```
|
||||
|
||||
配置文件 `vue.config.js` 增加 `configureWebpack.plugins` 参数
|
||||
|
||||
```
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
// vue.config.js
|
||||
module.exports = {
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
// Ignore all locale files of moment.js
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
// 依赖大小分析工具
|
||||
new BundleAnalyzerPlugin(),
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
启动 `cli` 的 `build` 命令进行项目编译,编译完成时,会自动运行一个 http://localhost:8888
|
||||
的地址,完整显示了支持库依赖
|
||||
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
'jsx',
|
||||
'json',
|
||||
'vue'
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
|
||||
'^.+\\.jsx?$': 'babel-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1'
|
||||
},
|
||||
snapshotSerializers: [
|
||||
'jest-serializer-vue'
|
||||
],
|
||||
testMatch: [
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||
],
|
||||
testURL: 'http://localhost/'
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dist"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# 日志格式
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
# 基本设置
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types
|
||||
text/plain
|
||||
text/css
|
||||
text/xml
|
||||
text/javascript
|
||||
application/json
|
||||
application/javascript
|
||||
application/xml+rss
|
||||
application/atom+xml
|
||||
image/svg+xml;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# API 代理到后端服务
|
||||
location /api/ {
|
||||
proxy_pass http://backend:9092/;
|
||||
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_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
}
|
||||
|
||||
# 健康检查
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
# 前端路由支持
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# 错误页面
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"name": "universal",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"lint": "vue-cli-service lint",
|
||||
"dev": "vue-cli-service serve",
|
||||
"start": "vue-cli-service serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||
"ant-design-vue": "^1.7.8",
|
||||
"axios": "^1.10.0",
|
||||
"codemirror": "^5.65.19",
|
||||
"concurrently": "^7.0.0",
|
||||
"core-js": "^3.19.2",
|
||||
"echarts": "^5.2.2",
|
||||
"ezuikit-flv": "^1.0.3-alpha.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"highlight.js": "^11.3.1",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.get": "^4.4.2",
|
||||
"lodash.pick": "^4.4.0",
|
||||
"md5": "^2.3.0",
|
||||
"mockjs2": "^1.0.8",
|
||||
"moment": "^2.29.1",
|
||||
"nprogress": "^0.2.0",
|
||||
"qs": "^6.10.1",
|
||||
"screenfull": "5.0.2",
|
||||
"sql-formatter": "^4.0.2",
|
||||
"store": "^2.0.12",
|
||||
"vue": "^2.6.11",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-codemirror": "^4.0.6",
|
||||
"vue-container-query": "^0.1.0",
|
||||
"vue-copy-to-clipboard": "^1.0.3",
|
||||
"vue-count-to": "^1.0.13",
|
||||
"vue-cropper": "0.5.8",
|
||||
"vue-i18n": "^8.24.2",
|
||||
"vue-json-viewer": "^2.2.21",
|
||||
"vue-resizable": "2.1.3",
|
||||
"vue-router": "^3.2.0",
|
||||
"vue-svg-component-runtime": "^1.0.1",
|
||||
"vuex": "^3.4.0",
|
||||
"wangeditor": "^4.7.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/colors": "^6.0.0",
|
||||
"@babel/eslint-parser": "^7.27.5",
|
||||
"@vue/cli-plugin-babel": "^4.0.4",
|
||||
"@vue/cli-plugin-router": "^4.0.4",
|
||||
"@vue/cli-plugin-unit-jest": "^4.0.4",
|
||||
"@vue/cli-plugin-vuex": "^4.0.4",
|
||||
"@vue/cli-service": "^4.0.4",
|
||||
"@vue/eslint-config-standard": "^4.0.0",
|
||||
"@vue/test-utils": "^1.3.0",
|
||||
"babel-plugin-import": "^1.12.2",
|
||||
"babel-plugin-transform-remove-console": "^6.9.4",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-plugin-html": "^5.0.0",
|
||||
"eslint-plugin-vue": "^8.7.1",
|
||||
"git-revision-webpack-plugin": "^3.0.6",
|
||||
"husky": "^7.0.4",
|
||||
"less": "^3.13.1",
|
||||
"less-loader": "^7.3.0",
|
||||
"lint-staged": "^12.1.3",
|
||||
"opencollective": "^1.0.3",
|
||||
"opencollective-postinstall": "^2.0.2",
|
||||
"vue-svg-icon-loader": "^2.1.1",
|
||||
"vue-template-compiler": "^2.7.16",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-theme-color-replacer": "^1.3.12"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,vue,md,jsx,css}": "eslint --cache --fix"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,439 @@
|
||||
/*//////////////////////////////////////////////////////////////////
|
||||
[ FONT ]*/
|
||||
|
||||
@font-face {
|
||||
font-family: Poppins-Regular;
|
||||
src: url('../fonts/poppins/Poppins-Regular.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Poppins-Medium;
|
||||
src: url('../fonts/poppins/Poppins-Medium.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Poppins-Bold;
|
||||
src: url('../fonts/poppins/Poppins-Bold.ttf');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: Poppins-SemiBold;
|
||||
src: url('../fonts/poppins/Poppins-SemiBold.ttf');
|
||||
}
|
||||
|
||||
.limiter {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
font-family: Poppins-Regular, sans-serif;
|
||||
}
|
||||
|
||||
.container-login100 {
|
||||
width: 100%;
|
||||
/* min-height: 100vh; */
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #f2f2f2;
|
||||
}
|
||||
|
||||
.wrap-login100 {
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
padding: 77px 55px 33px 55px;
|
||||
|
||||
box-shadow: 0 5px 10px 0px rgba(0, 0, 0, 0.1);
|
||||
-moz-box-shadow: 0 5px 10px 0px rgba(0, 0, 0, 0.1);
|
||||
-webkit-box-shadow: 0 5px 10px 0px rgba(0, 0, 0, 0.1);
|
||||
-o-box-shadow: 0 5px 10px 0px rgba(0, 0, 0, 0.1);
|
||||
-ms-box-shadow: 0 5px 10px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
[ Form ]*/
|
||||
|
||||
.login100-form {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login100-form-title {
|
||||
display: block;
|
||||
font-family: Poppins-Bold;
|
||||
font-size: 30px;
|
||||
color: #333333;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
.login100-form-title i {
|
||||
font-size: 60px;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
[ Input ]*/
|
||||
|
||||
.wrap-input100 {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
border-bottom: 2px solid #adadad;
|
||||
margin-bottom: 37px;
|
||||
}
|
||||
|
||||
.input100 {
|
||||
font-family: Poppins-Regular;
|
||||
font-size: 15px;
|
||||
color: #555555;
|
||||
line-height: 1.2;
|
||||
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
background: transparent;
|
||||
padding: 0 5px;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.input100::-webkit-input-placeholder {
|
||||
color: #adadad;
|
||||
}
|
||||
|
||||
.input100:-moz-placeholder {
|
||||
color: #adadad;
|
||||
}
|
||||
|
||||
.input100::-moz-placeholder {
|
||||
color: #adadad;
|
||||
}
|
||||
|
||||
.input100:-ms-input-placeholder {
|
||||
color: #adadad;
|
||||
}
|
||||
|
||||
/*---------------------------------------------*/
|
||||
.focus-input100 {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.focus-input100::before {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
|
||||
-webkit-transition: all 0.4s;
|
||||
-o-transition: all 0.4s;
|
||||
-moz-transition: all 0.4s;
|
||||
transition: all 0.4s;
|
||||
|
||||
background: #6a7dfe;
|
||||
background: -webkit-linear-gradient(left, #21d4fd, #b721ff);
|
||||
background: -o-linear-gradient(left, #21d4fd, #b721ff);
|
||||
background: -moz-linear-gradient(left, #21d4fd, #b721ff);
|
||||
background: linear-gradient(left, #21d4fd, #b721ff);
|
||||
}
|
||||
|
||||
.focus-input100::after {
|
||||
font-family: Poppins-Regular;
|
||||
font-size: 15px;
|
||||
color: #999999;
|
||||
line-height: 1.2;
|
||||
|
||||
content: attr(data-placeholder);
|
||||
display: block;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
left: 0px;
|
||||
padding-left: 5px;
|
||||
|
||||
-webkit-transition: all 0.4s;
|
||||
-o-transition: all 0.4s;
|
||||
-moz-transition: all 0.4s;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
.input100:focus + .focus-input100::after {
|
||||
top: -15px;
|
||||
}
|
||||
|
||||
.input100:focus + .focus-input100::before {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.has-val.input100 + .focus-input100::after {
|
||||
top: -15px;
|
||||
}
|
||||
|
||||
.has-val.input100 + .focus-input100::before {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*---------------------------------------------*/
|
||||
.btn-show-pass {
|
||||
font-size: 15px;
|
||||
color: #999999;
|
||||
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding-right: 5px;
|
||||
cursor: pointer;
|
||||
-webkit-transition: all 0.4s;
|
||||
-o-transition: all 0.4s;
|
||||
-moz-transition: all 0.4s;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
.btn-show-pass:hover {
|
||||
color: #6a7dfe;
|
||||
color: -webkit-linear-gradient(left, #21d4fd, #b721ff);
|
||||
color: -o-linear-gradient(left, #21d4fd, #b721ff);
|
||||
color: -moz-linear-gradient(left, #21d4fd, #b721ff);
|
||||
color: linear-gradient(left, #21d4fd, #b721ff);
|
||||
}
|
||||
|
||||
.btn-show-pass.active {
|
||||
color: #6a7dfe;
|
||||
color: -webkit-linear-gradient(left, #21d4fd, #b721ff);
|
||||
color: -o-linear-gradient(left, #21d4fd, #b721ff);
|
||||
color: -moz-linear-gradient(left, #21d4fd, #b721ff);
|
||||
color: linear-gradient(left, #21d4fd, #b721ff);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
[ Button ]*/
|
||||
.container-login100-form-btn {
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
padding-top: 13px;
|
||||
}
|
||||
|
||||
.wrap-login100-form-btn {
|
||||
width: 100%;
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border-radius: 25px;
|
||||
overflow: hidden;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.login100-form-bgbtn {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
width: 300%;
|
||||
height: 100%;
|
||||
background: #a64bf4;
|
||||
background: -webkit-linear-gradient(right, #21d4fd, #b721ff, #21d4fd, #b721ff);
|
||||
background: -o-linear-gradient(right, #21d4fd, #b721ff, #21d4fd, #b721ff);
|
||||
background: -moz-linear-gradient(right, #21d4fd, #b721ff, #21d4fd, #b721ff);
|
||||
background: linear-gradient(right, #21d4fd, #b721ff, #21d4fd, #b721ff);
|
||||
top: 0;
|
||||
left: -100%;
|
||||
|
||||
-webkit-transition: all 0.4s;
|
||||
-o-transition: all 0.4s;
|
||||
-moz-transition: all 0.4s;
|
||||
transition: all 0.4s;
|
||||
}
|
||||
|
||||
.login100-form-btn {
|
||||
font-family: Poppins-Medium;
|
||||
font-size: 15px;
|
||||
color: #fff;
|
||||
line-height: 1.2;
|
||||
text-transform: uppercase;
|
||||
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
outline: none !important;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.login100-form-btn:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wrap-login100-form-btn:hover .login100-form-bgbtn {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
[ Responsive ]*/
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.wrap-login100 {
|
||||
padding: 77px 15px 33px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------
|
||||
[ Alert validate ]*/
|
||||
|
||||
.validate-input {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.alert-validate::before {
|
||||
content: attr(data-validate);
|
||||
position: absolute;
|
||||
max-width: 70%;
|
||||
background-color: #fff;
|
||||
border: 1px solid #c80000;
|
||||
border-radius: 2px;
|
||||
padding: 4px 25px 4px 10px;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-moz-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-o-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
right: 0px;
|
||||
pointer-events: none;
|
||||
|
||||
font-family: Poppins-Regular;
|
||||
color: #c80000;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
text-align: left;
|
||||
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
||||
-webkit-transition: opacity 0.4s;
|
||||
-o-transition: opacity 0.4s;
|
||||
-moz-transition: opacity 0.4s;
|
||||
transition: opacity 0.4s;
|
||||
}
|
||||
|
||||
.alert-validate::after {
|
||||
content: "\f06a";
|
||||
font-family: FontAwesome;
|
||||
font-size: 16px;
|
||||
color: #c80000;
|
||||
|
||||
display: block;
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
-moz-transform: translateY(-50%);
|
||||
-ms-transform: translateY(-50%);
|
||||
-o-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.alert-validate:hover:before {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.alert-validate::before {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/** util **/
|
||||
.p-b-26 {
|
||||
padding-bottom: 26px;
|
||||
}
|
||||
|
||||
.p-b-48 {
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
|
||||
.p-t-115 {
|
||||
padding-top: 115px;
|
||||
}
|
||||
|
||||
@keyframes login {
|
||||
from {
|
||||
width: 100%
|
||||
}
|
||||
to {
|
||||
width: 50px
|
||||
}
|
||||
}
|
||||
|
||||
.login-loading {
|
||||
width: 50px;
|
||||
animation-name: login;
|
||||
animation-duration: 0.5s;
|
||||
}
|
||||
|
||||
.login-loading > .login100-form-btn {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
.login-loading-class {
|
||||
stroke: rgb(255, 255, 255) !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.login-loading-class > .el-loading-spinner .path {
|
||||
stroke: rgb(255, 255, 255) !important;
|
||||
}
|
||||
|
||||
|
||||
/**font**/
|
||||
/* .zmdi {
|
||||
display: inline-block;
|
||||
font: normal normal normal 14px/1 'Material-Design-Iconic-Font';
|
||||
font-size: 14px;
|
||||
font-size: inherit;
|
||||
text-rendering: auto;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
.zmdi-font::before {
|
||||
content: '\f16a';
|
||||
}
|
||||
.login100-form-title i {
|
||||
font-size: 60px;
|
||||
} */
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
Place EZVIZ decoder assets here if you use custom decoder path.
|
||||
|
||||
- Example: decoder.js and related wasm files
|
||||
- Then set decoder to "/ezviz/decoder.js" in EzuikitFlv options
|
||||
|
||||
Docs:
|
||||
- https://open.ys7.com/help/1812
|
||||
- https://ezviz-openbiz.github.io/EZUIKit-flv/global.html#FlvOptions
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
class AudioProcessor extends AudioWorkletProcessor{constructor(){super(),this.accumulatedData=new Float32Array(0)}process(t,a,s){const e=t[0]?.[0];if(e){const t=new Float32Array(this.accumulatedData.length+e.length);t.set(this.accumulatedData),t.set(e,this.accumulatedData.length),this.accumulatedData=t,this.accumulatedData.length>=4096&&(this.port.postMessage(this.accumulatedData.slice(0,4096)),this.accumulatedData=this.accumulatedData.slice(4096))}return!0}}registerProcessor("audio-processor",AudioProcessor);
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -0,0 +1 @@
|
||||
var Module={};function threadPrintErr(){var e=Array.prototype.slice.call(arguments).join(" ");console.error(e)}function threadAlert(){var e=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:e,threadId:Module._pthread_self()})}var err=threadPrintErr;function moduleLoaded(){}this.alert=threadAlert,Module.instantiateWasm=function(e,a){var t=new WebAssembly.Instance(Module.wasmModule,e);return Module.wasmModule=null,a(t),t.exports},this.onmessage=function(e){try{if("load"===e.data.cmd){if(Module.wasmModule=e.data.wasmModule,Module.wasmMemory=e.data.wasmMemory,Module.buffer=Module.wasmMemory.buffer,Module.ENVIRONMENT_IS_PTHREAD=!0,"string"===typeof e.data.urlOrBlob)importScripts(e.data.urlOrBlob);else{var a=URL.createObjectURL(e.data.urlOrBlob);importScripts(a),URL.revokeObjectURL(a)}moduleLoaded()}else if("objectTransfer"===e.data.cmd)Module.PThread.receiveObjectTransfer(e.data);else if("run"===e.data.cmd){Module.__performance_now_clock_drift=performance.now()-e.data.time,Module.__emscripten_thread_init(e.data.threadInfoStruct,0,0);var t=e.data.stackBase,r=e.data.stackBase+e.data.stackSize;Module.establishStackSpace(r,t),Module._emscripten_tls_init(),Module.PThread.receiveObjectTransfer(e.data),Module.PThread.setThreadStatus(Module._pthread_self(),1);try{var d=Module.invokeEntryPoint(e.data.start_routine,e.data.arg);Module.getNoExitRuntime()||Module.PThread.threadExit(d)}catch(e){if("Canceled!"===e)Module.PThread.threadCancel();else if("unwind"!=e){if(!(e instanceof Module.ExitStatus))throw Module.PThread.threadExit(-2),e;Module.getNoExitRuntime()||Module.PThread.threadExit(e.status)}}}else"cancel"===e.data.cmd?Module._pthread_self()&&Module.PThread.threadCancel():"setimmediate"===e.data.target||("processThreadQueue"===e.data.cmd?Module._pthread_self()&&Module._emscripten_current_thread_process_queued_calls():(err("worker.js received unknown command "+e.data.cmd),err(e.data)))}catch(e){throw err("worker.js onmessage() captured an uncaught exception: "+e),e&&e.stack&&err(e.stack),e}};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
+151
@@ -0,0 +1,151 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-cmn-Hans">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0"/>
|
||||
<link rel="icon" href="favicon.ico"/>
|
||||
<!-- jessibuca begin -->
|
||||
<link rel="stylesheet" type="text/css" href="/css/iconfont.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/login.css">
|
||||
<!-- jessibuca end -->
|
||||
<title>IoT Universal</title>
|
||||
<style>
|
||||
.first-loading-wrp {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
min-height: 420px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.first-loading-wrp > h1 {
|
||||
font-size: 128px;
|
||||
}
|
||||
|
||||
.first-loading-wrp .loading-wrp {
|
||||
padding: 98px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dot {
|
||||
animation: antRotate 1.2s infinite linear;
|
||||
transform: rotate(45deg);
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dot i {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: absolute;
|
||||
display: block;
|
||||
background-color: #1890ff;
|
||||
border-radius: 100%;
|
||||
transform: scale(0.75);
|
||||
transform-origin: 50% 50%;
|
||||
opacity: 0.3;
|
||||
animation: antSpinMove 1s infinite linear alternate;
|
||||
}
|
||||
|
||||
.dot i:nth-child(1) {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.dot i:nth-child(2) {
|
||||
top: 0;
|
||||
right: 0;
|
||||
-webkit-animation-delay: 0.4s;
|
||||
animation-delay: 0.4s;
|
||||
}
|
||||
|
||||
.dot i:nth-child(3) {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
-webkit-animation-delay: 0.8s;
|
||||
animation-delay: 0.8s;
|
||||
}
|
||||
|
||||
.dot i:nth-child(4) {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
-webkit-animation-delay: 1.2s;
|
||||
animation-delay: 1.2s;
|
||||
}
|
||||
|
||||
@keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antRotate {
|
||||
to {
|
||||
-webkit-transform: rotate(405deg);
|
||||
transform: rotate(405deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes antSpinMove {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.amap-logo,
|
||||
.amap-copyright {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
<!-- require cdn assets css -->
|
||||
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
|
||||
<link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"/>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>请启用JavaScript后再使用IoT Platform</strong>
|
||||
</noscript>
|
||||
|
||||
<script type="text/javascript">
|
||||
// window._AMapSecurityConfig = {
|
||||
// serviceHost: 'https://map.universal.cn/_AMapService',
|
||||
// }
|
||||
window._AMapSecurityConfig = {
|
||||
securityJsCode: "139244dd5f5f4dec671214637f3f83bd",
|
||||
};
|
||||
</script>
|
||||
|
||||
<div id="app">
|
||||
<div class="first-loading-wrp">
|
||||
<div class="loading-wrp">
|
||||
<span class="dot dot-spin"><i></i><i></i><i></i><i></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- require cdn assets js -->
|
||||
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
|
||||
<script type="text/javascript" src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
|
||||
<% } %>
|
||||
<!-- built files will be auto injected -->
|
||||
|
||||
<!-- jessibuca -->
|
||||
<script type="text/javascript" src="/js/jessibucaPro/jessibuca-pro-demo.js"></script>
|
||||
<!-- jessibuca -->
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1 @@
|
||||
"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:f=>(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason||e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./decoder-pro-mt-worker.js")).then(exports=>exports.default(Module))}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err(`worker.js received unknown command ${e.data.cmd}`);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1 @@
|
||||
"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:f=>(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason||e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./decoder-pro-simd-mt-worker.js")).then(exports=>exports.default(Module))}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err(`worker.js received unknown command ${e.data.cmd}`);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
<svg width="120" height="32" viewBox="0 0 120 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- 主要图标部分 -->
|
||||
<g id="logo-icon">
|
||||
<!-- 中心核心 -->
|
||||
<circle cx="16" cy="16" r="3" fill="#3370ff"/>
|
||||
|
||||
<!-- 连接节点 -->
|
||||
<circle cx="6" cy="8" r="2" fill="#3370ff" opacity="0.8"/>
|
||||
<circle cx="26" cy="8" r="2" fill="#3370ff" opacity="0.8"/>
|
||||
<circle cx="6" cy="24" r="2" fill="#3370ff" opacity="0.8"/>
|
||||
<circle cx="26" cy="24" r="2" fill="#3370ff" opacity="0.8"/>
|
||||
|
||||
<!-- 连接线 -->
|
||||
<line x1="8" y1="9" x2="14" y2="14" stroke="#3370ff" stroke-width="1.5" opacity="0.6"/>
|
||||
<line x1="24" y1="9" x2="18" y2="14" stroke="#3370ff" stroke-width="1.5" opacity="0.6"/>
|
||||
<line x1="8" y1="23" x2="14" y2="18" stroke="#3370ff" stroke-width="1.5" opacity="0.6"/>
|
||||
<line x1="24" y1="23" x2="18" y2="18" stroke="#3370ff" stroke-width="1.5" opacity="0.6"/>
|
||||
|
||||
<!-- 数据流动效果 -->
|
||||
<circle cx="10" cy="11" r="1" fill="#00d4aa" opacity="0.9">
|
||||
<animate attributeName="opacity" values="0.3;1;0.3" dur="2s" repeatCount="indefinite"/>
|
||||
</circle>
|
||||
<circle cx="22" cy="11" r="1" fill="#00d4aa" opacity="0.9">
|
||||
<animate attributeName="opacity" values="1;0.3;1" dur="2s" repeatCount="indefinite"/>
|
||||
</circle>
|
||||
</g>
|
||||
|
||||
<!-- 文字部分 -->
|
||||
<g id="logo-text">
|
||||
<text x="40" y="20" font-family="PingFang SC, Microsoft YaHei, sans-serif" font-size="13"
|
||||
font-weight="600" fill="#1d2129">IoT Platform
|
||||
</text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<a-config-provider :locale="locale">
|
||||
<div id="app">
|
||||
<router-view/>
|
||||
<Resizabler ref="resizabler"/>
|
||||
</div>
|
||||
</a-config-provider>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {domTitle, setDocumentTitle} from '@/utils/domUtil'
|
||||
import {i18nRender} from '@/locales'
|
||||
import Resizabler from '@/views/dashboard/components/Resizabler.vue'
|
||||
|
||||
export default {
|
||||
components: {Resizabler},
|
||||
computed: {
|
||||
locale() {
|
||||
// 只是为了切换语言时,更新标题
|
||||
const {title} = this.$route.meta
|
||||
title && (setDocumentTitle(`${i18nRender(title)} - ${domTitle}`))
|
||||
|
||||
return this.$i18n.getLocaleMessage(this.$store.getters.lang).antLocale
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$bus.$on('resizeabler', (queryName) => {
|
||||
this.$refs.resizabler.open(queryName)
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,79 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询用户应用信息列表
|
||||
export function listApplication(query) {
|
||||
return request({
|
||||
url: '/admin/v1/apply/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询用户应用信息详细
|
||||
export function getApplication(uuid) {
|
||||
return request({
|
||||
url: '/admin/v1/apply/' + uuid,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增用户应用信息
|
||||
export function addApplication(data) {
|
||||
return request({
|
||||
url: '/admin/v1/apply',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改用户应用信息
|
||||
export function updateApplication(data) {
|
||||
return request({
|
||||
url: '/admin/v1/apply',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改用户应用信息
|
||||
export function enable(data) {
|
||||
return request({
|
||||
url: '/admin/v1/apply/enable',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除用户应用信息
|
||||
export function delApplication(uuid) {
|
||||
return request({
|
||||
url: '/admin/v1/apply/' + uuid,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 重置密钥
|
||||
export function resetSecret(data) {
|
||||
return request({
|
||||
url: '/admin/v1/apply/reset',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 地址测试
|
||||
export function checkUrl(query) {
|
||||
return request({
|
||||
url: '/admin/v1/apply/check',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 启用/停用推送配置
|
||||
export function enableOrDisablePush(appUniqueId, pushType, enable) {
|
||||
return request({
|
||||
url: `/admin/v1/apply/${appUniqueId}/${pushType}/${enable}`,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取仪表盘概览数据
|
||||
export function getDashboardOverview() {
|
||||
return request({
|
||||
url: '/dashboard/overview',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取设备消息分类图表数据
|
||||
export function getDashboardMessageClassification(timeRange = 'today') {
|
||||
return request({
|
||||
url: '/api/dashboard/message-classification',
|
||||
method: 'get',
|
||||
params: {timeRange}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取系统性能监控数据
|
||||
export function getDashboardSystemMonitor(refreshInterval = 5) {
|
||||
return request({
|
||||
url: '/api/dashboard/system-monitor',
|
||||
method: 'get',
|
||||
params: {refreshInterval}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取实时数据(兼容旧接口)
|
||||
export function getDashboardRealtime() {
|
||||
return request({
|
||||
url: '/dashboard/realtime',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取告警数据(兼容旧接口)
|
||||
export function getDashboardAlerts(params) {
|
||||
return request({
|
||||
url: '/dashboard/alerts',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户活动数据(兼容旧接口)
|
||||
export function getDashboardUserActivity(params) {
|
||||
return request({
|
||||
url: '/dashboard/user-activity',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取图表数据(兼容旧接口)
|
||||
export function getDashboardChartData(params) {
|
||||
return request({
|
||||
url: '/dashboard/chart-data',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取设备统计(兼容旧接口)
|
||||
export function getDashboardDeviceStats(params) {
|
||||
return request({
|
||||
url: '/dashboard/device-stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取消息统计(兼容旧接口)
|
||||
export function getDashboardMessageStats(params) {
|
||||
return request({
|
||||
url: '/dashboard/message-stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取渠道统计(兼容旧接口)
|
||||
export function getDashboardChannelStats(params) {
|
||||
return request({
|
||||
url: '/dashboard/channel-stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取小时统计(兼容旧接口)
|
||||
export function getDashboardHourlyStats(params) {
|
||||
return request({
|
||||
url: '/dashboard/hourly-stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取应用统计(兼容旧接口)
|
||||
export function getDashboardAppStats(params) {
|
||||
return request({
|
||||
url: '/dashboard/app-stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取产品统计(兼容旧接口)
|
||||
export function getDashboardProductStats(params) {
|
||||
return request({
|
||||
url: '/dashboard/product-stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 获取规则统计(兼容旧接口)
|
||||
export function getDashboardRuleStats(params) {
|
||||
return request({
|
||||
url: '/dashboard/rule-stats',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 国标应用列表
|
||||
* @param {*} params
|
||||
* @returns
|
||||
*/
|
||||
export function getGBAppList(params) {
|
||||
return request({
|
||||
url: '/admin/wvpThirdApplication/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
/**
|
||||
* 查询摄像头列表
|
||||
* @param {*} query
|
||||
* @returns
|
||||
*/
|
||||
export function getCameraList(query) {
|
||||
return request({
|
||||
url: '/admin/wvpDevice/page',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加摄像头
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function addDevice(data) {
|
||||
return request({
|
||||
url: '/admin/wvpDevice',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除摄像头
|
||||
* @param {*} ids
|
||||
* @returns
|
||||
*/
|
||||
export function removeDevice(ids) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/${ids}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改摄像头
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function modifyDevice(data) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备详情
|
||||
* @param {*} id
|
||||
* @returns
|
||||
*/
|
||||
export function deviceDetail(id) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询流媒体节点
|
||||
*/
|
||||
export function getMediaIds() {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/media`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备通道列表
|
||||
* @param {*} deviceId
|
||||
* @returns
|
||||
*/
|
||||
export function getChannelList(deviceId) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/channel/${deviceId}`,
|
||||
method: 'get',
|
||||
params: {
|
||||
deviceId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 通道修改
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
export function modifyChannel(data) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/channel`,
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 摄像头取流
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @returns
|
||||
*/
|
||||
export function getPlayUrl(deviceId, channelId) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/play/${deviceId}/${channelId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止取流
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @returns
|
||||
*/
|
||||
export function stopPlayLive(deviceId, channelId) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/stop/${deviceId}/${channelId}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入
|
||||
* @param {*} productKey
|
||||
* @returns
|
||||
*/
|
||||
export function handleBatchImport(productKey, data) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/import`,
|
||||
method: 'post',
|
||||
params: {
|
||||
productKey
|
||||
},
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 摄像头获取本地录像列表
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} startTime
|
||||
* @param {*} endTime
|
||||
* @returns
|
||||
*/
|
||||
export function getDeviceVideoTapeList(deviceId, channelId, startTime,
|
||||
endTime) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/list/${deviceId}/${channelId}`,
|
||||
method: 'get',
|
||||
params: {
|
||||
startTime,
|
||||
endTime
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取本地录像段
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} startTime
|
||||
* @param {*} endTime
|
||||
* @returns
|
||||
*/
|
||||
export function getDeviceVideoTapeCtx(deviceId, channelId, startTime, endTime) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/play/${deviceId}/${channelId}`,
|
||||
method: 'get',
|
||||
params: {
|
||||
startTime,
|
||||
endTime
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 倍速播放本地录像
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} stream
|
||||
* @param {*} speed
|
||||
* @returns
|
||||
*/
|
||||
export function getScaleDeviceVideoTapeCtx(deviceId, channelId, stream, speed) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/speed/${deviceId}/${channelId}/${stream}/${speed}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止播放本地录像
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} stream
|
||||
* @returns
|
||||
*/
|
||||
export function stopDeviceVideoTape(deviceId, channelId, stream) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/stop/${deviceId}/${channelId}/${stream}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停播放本地录像
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} stream
|
||||
* @returns
|
||||
*/
|
||||
export function pauseDeviceVideoTape(deviceId, channelId, stream) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/pause/${deviceId}/${channelId}/${stream}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复播放本地录像
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} stream
|
||||
* @returns
|
||||
*/
|
||||
export function resumeDeviceVideoTape(deviceId, channelId, stream) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/resume/${deviceId}/${channelId}/${stream}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始下载本地录像
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} startTime
|
||||
* @param {*} endTime
|
||||
* @param {*} downloadSpeed 倍速
|
||||
* @returns
|
||||
*/
|
||||
export function downloadDeviceVideoTape(deviceId, channelId, startTime, endTime,
|
||||
downloadSpeed = 128) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/download/start/${deviceId}/${channelId}`,
|
||||
method: 'get',
|
||||
params: {
|
||||
startTime,
|
||||
endTime,
|
||||
downloadSpeed
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备录像下载进度
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} stream
|
||||
* @returns
|
||||
*/
|
||||
export function getDownloadDeviceProgress(deviceId, channelId, stream) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/local/record/download/progress/${deviceId}/${channelId}/${stream}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 摄像头获取云端录像列表
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @returns
|
||||
*/
|
||||
export function getCloudVideoTapeList(deviceId, channelId, startTime, endTime) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/cloud/record/list/${deviceId}/${channelId}`,
|
||||
method: 'get',
|
||||
params: {
|
||||
startTime,
|
||||
endTime
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取云端录像片段
|
||||
* @param {*} deviceId
|
||||
* @param {*} channelId
|
||||
* @param {*} recordId
|
||||
* @returns
|
||||
*/
|
||||
export function getCloudVideoTapeCtx(deviceId, channelId, recordId) {
|
||||
return request({
|
||||
url: `/admin/wvpDevice/cloud/record/play/${deviceId}/${channelId}`,
|
||||
method: 'get',
|
||||
params: {
|
||||
recordId
|
||||
}
|
||||
})
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user