impl: 添加一个数据测试工具(rition-testsuite,用于从测试数据中模拟数据上传情况) doc: 补充建表sql todo: 前端面板立项main
@ -0,0 +1,103 @@ |
|||||||
|
/* |
||||||
|
Navicat Premium Data Transfer |
||||||
|
|
||||||
|
Source Server : mysql |
||||||
|
Source Server Type : MySQL |
||||||
|
Source Server Version : 80027 (8.0.27) |
||||||
|
Source Host : 127.0.0.1:3306 |
||||||
|
Source Schema : rition |
||||||
|
|
||||||
|
Target Server Type : MySQL |
||||||
|
Target Server Version : 80027 (8.0.27) |
||||||
|
File Encoding : 65001 |
||||||
|
|
||||||
|
Date: 08/05/2024 10:15:09 |
||||||
|
*/ |
||||||
|
|
||||||
|
SET NAMES utf8mb4; |
||||||
|
SET FOREIGN_KEY_CHECKS = 0; |
||||||
|
|
||||||
|
-- ---------------------------- |
||||||
|
-- Table structure for alert |
||||||
|
-- ---------------------------- |
||||||
|
DROP TABLE IF EXISTS `alert`; |
||||||
|
CREATE TABLE `alert` ( |
||||||
|
`id` bigint NOT NULL, |
||||||
|
`instance_id` varchar(64) NOT NULL COMMENT '出现警告的实例id', |
||||||
|
`rule` bigint NOT NULL COMMENT '触发的规则', |
||||||
|
`time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '警告出现的时间', |
||||||
|
`status` tinyint NOT NULL DEFAULT '0', |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
KEY `idx_instance` (`instance_id`), |
||||||
|
KEY `idx_rule` (`rule`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
-- ---------------------------- |
||||||
|
-- Table structure for contract |
||||||
|
-- ---------------------------- |
||||||
|
DROP TABLE IF EXISTS `contract`; |
||||||
|
CREATE TABLE `contract` ( |
||||||
|
`id` bigint NOT NULL, |
||||||
|
`instance_id` varchar(64) NOT NULL COMMENT '绑定的实例', |
||||||
|
`contract` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '联系方式', |
||||||
|
`type` tinyint NOT NULL COMMENT '联系方式类型', |
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, |
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||||
|
`status` tinyint NOT NULL DEFAULT '0', |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
KEY `idx_id` (`id`), |
||||||
|
KEY `idx_instance` (`instance_id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
-- ---------------------------- |
||||||
|
-- Table structure for ecs |
||||||
|
-- ---------------------------- |
||||||
|
DROP TABLE IF EXISTS `ecs`; |
||||||
|
CREATE TABLE `ecs` ( |
||||||
|
`id` varchar(128) NOT NULL COMMENT '实例id', |
||||||
|
`name` varchar(255) NOT NULL COMMENT '主机名称', |
||||||
|
`ip` varchar(15) NOT NULL COMMENT '主机绑定分配的ip', |
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, |
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||||
|
`status` tinyint NOT NULL DEFAULT '0', |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
KEY `idx_id` (`id`), |
||||||
|
KEY `idx_ip` (`ip`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
-- ---------------------------- |
||||||
|
-- Table structure for record |
||||||
|
-- ---------------------------- |
||||||
|
DROP TABLE IF EXISTS `record`; |
||||||
|
CREATE TABLE `record` ( |
||||||
|
`id` bigint NOT NULL, |
||||||
|
`instance_id` varchar(64) NOT NULL COMMENT '实例id', |
||||||
|
`metric_data` json NOT NULL COMMENT '监控指标值,使用json格式存储', |
||||||
|
`time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '数据时间', |
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||||
|
`status` tinyint NOT NULL DEFAULT '0', |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
KEY `idx_id` (`id`), |
||||||
|
KEY `idx_time` (`time`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
-- ---------------------------- |
||||||
|
-- Table structure for rule |
||||||
|
-- ---------------------------- |
||||||
|
DROP TABLE IF EXISTS `rule`; |
||||||
|
CREATE TABLE `rule` ( |
||||||
|
`id` bigint NOT NULL COMMENT '规则id', |
||||||
|
`instance_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '规则对应的实例id', |
||||||
|
`expression` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '需要计算的指标项或者表达式', |
||||||
|
`condition` tinyint NOT NULL COMMENT '触发条件', |
||||||
|
`threshold` varchar(32) NOT NULL COMMENT '阈值', |
||||||
|
`trigger` tinyint NOT NULL COMMENT '触发方法,实时计算或定时计算', |
||||||
|
`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '' COMMENT '规则描述', |
||||||
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, |
||||||
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
||||||
|
`status` tinyint NOT NULL DEFAULT '0', |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
KEY `idx_instance` (`instance_id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; |
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1; |
@ -0,0 +1,13 @@ |
|||||||
|
package rition.backend.api.v1.dto.request; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
@Data |
||||||
|
public class MetricDataRequest { |
||||||
|
private String instanceId; |
||||||
|
private Long start; |
||||||
|
private Long end; |
||||||
|
private List<String> metricItems; |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
package rition.backend.api.v1.panel; |
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
import rition.backend.api.v1.dto.request.MetricDataRequest; |
||||||
|
import rition.backend.api.v1.dto.response.Response; |
||||||
|
|
||||||
|
@RestController |
||||||
|
@RequestMapping("/panel/metrics") |
||||||
|
public class MetricsViewController { |
||||||
|
|
||||||
|
@GetMapping("/list") |
||||||
|
public Response<Object> getMetrics(@RequestBody MetricDataRequest metricDataRequest) { |
||||||
|
return Response.success(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package rition.backend.api.v1.panel; |
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
@RestController |
||||||
|
@RequestMapping("/panel") |
||||||
|
public class PanelController { |
||||||
|
|
||||||
|
} |
@ -1,4 +1,18 @@ |
|||||||
package rition.service.monitor; |
package rition.service.monitor; |
||||||
|
|
||||||
|
import org.apache.kafka.clients.consumer.ConsumerRecord; |
||||||
|
import org.springframework.kafka.annotation.KafkaListener; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import rition.common.data.dto.MetricDataDto; |
||||||
|
|
||||||
|
@Service |
||||||
public class MonitorService { |
public class MonitorService { |
||||||
|
|
||||||
|
@KafkaListener( |
||||||
|
topics = {"${rition.kafka.data-collecting.topic}"}, |
||||||
|
groupId = "${rition.kafka.data-collecting.group}" |
||||||
|
) |
||||||
|
public void processMetricData(ConsumerRecord<String, MetricDataDto> metricDataConsumerRecord) { |
||||||
|
|
||||||
|
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,25 @@ |
|||||||
|
package rition.service.monitor.configure; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
@Data |
||||||
|
@Configuration |
||||||
|
@ConfigurationProperties("rition.kafka") |
||||||
|
public class MonitorServiceKafkaConfigure { |
||||||
|
private DataCollectingKafkaConfig dataCollecting; |
||||||
|
private AlertMessageKafkaConfig alertMessageKafkaConfig; |
||||||
|
|
||||||
|
@Data |
||||||
|
public static class DataCollectingKafkaConfig { |
||||||
|
private String topic; |
||||||
|
private String group; |
||||||
|
} |
||||||
|
|
||||||
|
@Data |
||||||
|
public static class AlertMessageKafkaConfig { |
||||||
|
private String topic; |
||||||
|
private String group; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
spring: |
||||||
|
datasource: |
||||||
|
driver-class-name: com.mysql.cj.jdbc.Driver |
||||||
|
url: jdbc:mysql://127.0.0.1:3306/rition?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true |
||||||
|
username: root |
||||||
|
password: Test2333! |
||||||
|
kafka: |
||||||
|
bootstrap-servers: '127.0.0.1:9092' |
||||||
|
consumer: |
||||||
|
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer |
||||||
|
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer |
||||||
|
properties: |
||||||
|
spring: |
||||||
|
json: |
||||||
|
trusted: |
||||||
|
packages: "rition.common.data.dto" |
||||||
|
producer: |
||||||
|
retries: 4 |
||||||
|
compression-type: zstd |
||||||
|
key-serializer: org.apache.kafka.common.serialization.StringSerializer |
||||||
|
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer |
||||||
|
acks: 1 |
||||||
|
properties: |
||||||
|
linger: |
||||||
|
ms: 200 |
||||||
|
|
||||||
|
rition: |
||||||
|
kafka: |
||||||
|
data-collecting: |
||||||
|
topic: 'ecs-metric-data-topic' |
||||||
|
group: 'ecs-metric-data-group' |
@ -0,0 +1,23 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||||
|
<modelVersion>4.0.0</modelVersion> |
||||||
|
<parent> |
||||||
|
<groupId>net.rition</groupId> |
||||||
|
<artifactId>service</artifactId> |
||||||
|
<version>${revision}</version> |
||||||
|
</parent> |
||||||
|
|
||||||
|
<artifactId>panel</artifactId> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<maven.compiler.source>17</maven.compiler.source> |
||||||
|
<maven.compiler.target>17</maven.compiler.target> |
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
|
||||||
|
</dependencies> |
||||||
|
</project> |
@ -0,0 +1,7 @@ |
|||||||
|
package rition.service.panel; |
||||||
|
|
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
@Service |
||||||
|
public class PanelService { |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
root = true |
||||||
|
|
||||||
|
[*] |
||||||
|
charset = utf-8 |
||||||
|
indent_style = space |
||||||
|
indent_size = 2 |
||||||
|
end_of_line = lf |
||||||
|
insert_final_newline = true |
||||||
|
trim_trailing_whitespace = true |
@ -0,0 +1,7 @@ |
|||||||
|
/dist |
||||||
|
/src-capacitor |
||||||
|
/src-cordova |
||||||
|
/.quasar |
||||||
|
/node_modules |
||||||
|
.eslintrc.cjs |
||||||
|
/quasar.config.*.temporary.compiled* |
@ -0,0 +1,65 @@ |
|||||||
|
module.exports = { |
||||||
|
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy |
||||||
|
// This option interrupts the configuration hierarchy at this file |
||||||
|
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos) |
||||||
|
root: true, |
||||||
|
|
||||||
|
parserOptions: { |
||||||
|
ecmaVersion: 2021, // Allows for the parsing of modern ECMAScript features |
||||||
|
}, |
||||||
|
|
||||||
|
env: { |
||||||
|
node: true, |
||||||
|
browser: true |
||||||
|
}, |
||||||
|
|
||||||
|
// Rules order is important, please avoid shuffling them |
||||||
|
extends: [ |
||||||
|
// Base ESLint recommended rules |
||||||
|
// 'eslint:recommended', |
||||||
|
|
||||||
|
// Uncomment any of the lines below to choose desired strictness, |
||||||
|
// but leave only one uncommented! |
||||||
|
// See https://eslint.vuejs.org/rules/#available-rules |
||||||
|
'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention) |
||||||
|
// 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability) |
||||||
|
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) |
||||||
|
|
||||||
|
// https://github.com/prettier/eslint-config-prettier#installation |
||||||
|
// usage with Prettier, provided by 'eslint-config-prettier'. |
||||||
|
'prettier' |
||||||
|
], |
||||||
|
|
||||||
|
plugins: [ |
||||||
|
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files |
||||||
|
// required to lint *.vue files |
||||||
|
'vue', |
||||||
|
|
||||||
|
// https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674 |
||||||
|
// Prettier has not been included as plugin to avoid performance impact |
||||||
|
// add it as an extension for your IDE |
||||||
|
|
||||||
|
], |
||||||
|
|
||||||
|
globals: { |
||||||
|
ga: 'readonly', // Google Analytics |
||||||
|
cordova: 'readonly', |
||||||
|
__statics: 'readonly', |
||||||
|
__QUASAR_SSR__: 'readonly', |
||||||
|
__QUASAR_SSR_SERVER__: 'readonly', |
||||||
|
__QUASAR_SSR_CLIENT__: 'readonly', |
||||||
|
__QUASAR_SSR_PWA__: 'readonly', |
||||||
|
process: 'readonly', |
||||||
|
Capacitor: 'readonly', |
||||||
|
chrome: 'readonly' |
||||||
|
}, |
||||||
|
|
||||||
|
// add your custom rules here |
||||||
|
rules: { |
||||||
|
|
||||||
|
'prefer-promise-reject-errors': 'off', |
||||||
|
|
||||||
|
// allow debugger during development only |
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' |
||||||
|
} |
||||||
|
} |
@ -1,24 +1,33 @@ |
|||||||
# Logs |
.DS_Store |
||||||
logs |
.thumbs.db |
||||||
*.log |
node_modules |
||||||
|
|
||||||
|
# Quasar core related directories |
||||||
|
.quasar |
||||||
|
/dist |
||||||
|
/quasar.config.*.temporary.compiled* |
||||||
|
|
||||||
|
# Cordova related directories and files |
||||||
|
/src-cordova/node_modules |
||||||
|
/src-cordova/platforms |
||||||
|
/src-cordova/plugins |
||||||
|
/src-cordova/www |
||||||
|
|
||||||
|
# Capacitor related directories and files |
||||||
|
/src-capacitor/www |
||||||
|
/src-capacitor/node_modules |
||||||
|
|
||||||
|
# Log files |
||||||
npm-debug.log* |
npm-debug.log* |
||||||
yarn-debug.log* |
yarn-debug.log* |
||||||
yarn-error.log* |
yarn-error.log* |
||||||
pnpm-debug.log* |
|
||||||
lerna-debug.log* |
|
||||||
|
|
||||||
node_modules |
|
||||||
dist |
|
||||||
dist-ssr |
|
||||||
*.local |
|
||||||
|
|
||||||
# Editor directories and files |
# Editor directories and files |
||||||
.vscode/* |
|
||||||
!.vscode/extensions.json |
|
||||||
.idea |
.idea |
||||||
.DS_Store |
|
||||||
*.suo |
*.suo |
||||||
*.ntvs* |
*.ntvs* |
||||||
*.njsproj |
*.njsproj |
||||||
*.sln |
*.sln |
||||||
*.sw? |
|
||||||
|
# local .env files |
||||||
|
.env.local* |
||||||
|
@ -0,0 +1,5 @@ |
|||||||
|
# pnpm-related options |
||||||
|
shamefully-hoist=true |
||||||
|
strict-peer-dependencies=false |
||||||
|
# to get the latest compatible packages when creating the project https://github.com/pnpm/pnpm/issues/6463 |
||||||
|
resolution-mode=highest |
@ -1,3 +1,3 @@ |
|||||||
# rition-panel |
# RitionPanel |
||||||
|
|
||||||
rition的面板 |
Panel of Rition project |
||||||
|
@ -1,13 +1,21 @@ |
|||||||
<!doctype html> |
<!DOCTYPE html> |
||||||
<html lang="en"> |
<html> |
||||||
<head> |
<head> |
||||||
<meta charset="UTF-8" /> |
<title><%= productName %></title> |
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
<meta charset="utf-8"> |
||||||
<title>Vite + Vue</title> |
<meta name="description" content="<%= productDescription %>"> |
||||||
|
<meta name="format-detection" content="telephone=no"> |
||||||
|
<meta name="msapplication-tap-highlight" content="no"> |
||||||
|
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"> |
||||||
|
|
||||||
|
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png"> |
||||||
|
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png"> |
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png"> |
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png"> |
||||||
|
<link rel="icon" type="image/ico" href="favicon.ico"> |
||||||
</head> |
</head> |
||||||
<body> |
<body> |
||||||
<div id="app"></div> |
<!-- quasar:entry-point --> |
||||||
<script type="module" src="/src/main.js"></script> |
|
||||||
</body> |
</body> |
||||||
</html> |
</html> |
||||||
|
@ -0,0 +1,39 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"baseUrl": ".", |
||||||
|
"paths": { |
||||||
|
"src/*": [ |
||||||
|
"src/*" |
||||||
|
], |
||||||
|
"app/*": [ |
||||||
|
"*" |
||||||
|
], |
||||||
|
"components/*": [ |
||||||
|
"src/components/*" |
||||||
|
], |
||||||
|
"layouts/*": [ |
||||||
|
"src/layouts/*" |
||||||
|
], |
||||||
|
"pages/*": [ |
||||||
|
"src/pages/*" |
||||||
|
], |
||||||
|
"assets/*": [ |
||||||
|
"src/assets/*" |
||||||
|
], |
||||||
|
"boot/*": [ |
||||||
|
"src/boot/*" |
||||||
|
], |
||||||
|
"stores/*": [ |
||||||
|
"src/stores/*" |
||||||
|
], |
||||||
|
"vue$": [ |
||||||
|
"node_modules/vue/dist/vue.runtime.esm-bundler.js" |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"exclude": [ |
||||||
|
"dist", |
||||||
|
".quasar", |
||||||
|
"node_modules" |
||||||
|
] |
||||||
|
} |
@ -1,18 +1,37 @@ |
|||||||
{ |
{ |
||||||
"name": "rition-panel", |
"name": "rition-panel", |
||||||
|
"version": "0.0.1", |
||||||
|
"description": "Panel of Rition project", |
||||||
|
"productName": "RitionPanel", |
||||||
|
"author": "lensfrex <lensferno@outlook.com>", |
||||||
"private": true, |
"private": true, |
||||||
"version": "0.0.0", |
|
||||||
"type": "module", |
|
||||||
"scripts": { |
"scripts": { |
||||||
"dev": "vite", |
"lint": "eslint --ext .js,.vue ./", |
||||||
"build": "vite build", |
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore", |
||||||
"preview": "vite preview" |
"test": "echo \"No test specified\" && exit 0", |
||||||
|
"dev": "quasar dev", |
||||||
|
"build": "quasar build" |
||||||
}, |
}, |
||||||
"dependencies": { |
"dependencies": { |
||||||
"vue": "^3.4.21" |
"axios": "^1.2.1", |
||||||
|
"@quasar/extras": "^1.16.4", |
||||||
|
"quasar": "^2.16.0", |
||||||
|
"vue": "^3.4.18", |
||||||
|
"vue-router": "^4.0.12" |
||||||
}, |
}, |
||||||
"devDependencies": { |
"devDependencies": { |
||||||
"@vitejs/plugin-vue": "^5.0.4", |
"eslint": "^8.57.0", |
||||||
"vite": "^5.2.0" |
"eslint-plugin-vue": "^9.0.0", |
||||||
|
"vite-plugin-checker": "^0.6.4", |
||||||
|
"eslint-config-prettier": "^8.1.0", |
||||||
|
"prettier": "^2.5.1", |
||||||
|
"@quasar/app-vite": "^1.9.0", |
||||||
|
"autoprefixer": "^10.4.2", |
||||||
|
"postcss": "^8.4.14" |
||||||
|
}, |
||||||
|
"engines": { |
||||||
|
"node": "^20 || ^18 || ^16", |
||||||
|
"npm": ">= 6.13.4", |
||||||
|
"yarn": ">= 1.21.1" |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,27 @@ |
|||||||
|
/* eslint-disable */ |
||||||
|
// https://github.com/michael-ciniawsky/postcss-load-config |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
plugins: [ |
||||||
|
// https://github.com/postcss/autoprefixer |
||||||
|
require('autoprefixer')({ |
||||||
|
overrideBrowserslist: [ |
||||||
|
'last 4 Chrome versions', |
||||||
|
'last 4 Firefox versions', |
||||||
|
'last 4 Edge versions', |
||||||
|
'last 4 Safari versions', |
||||||
|
'last 4 Android versions', |
||||||
|
'last 4 ChromeAndroid versions', |
||||||
|
'last 4 FirefoxAndroid versions', |
||||||
|
'last 4 iOS versions' |
||||||
|
] |
||||||
|
}) |
||||||
|
|
||||||
|
// https://github.com/elchininet/postcss-rtlcss |
||||||
|
// If you want to support RTL css, then |
||||||
|
// 1. yarn/npm install postcss-rtlcss |
||||||
|
// 2. optionally set quasar.config.js > framework > lang to an RTL language |
||||||
|
// 3. uncomment the following line: |
||||||
|
// require('postcss-rtlcss') |
||||||
|
] |
||||||
|
} |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 859 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,207 @@ |
|||||||
|
/* eslint-env node */ |
||||||
|
|
||||||
|
/* |
||||||
|
* This file runs in a Node context (it's NOT transpiled by Babel), so use only |
||||||
|
* the ES6 features that are supported by your Node version. https://node.green/
|
||||||
|
*/ |
||||||
|
|
||||||
|
// Configuration for your app
|
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
|
||||||
|
|
||||||
|
|
||||||
|
const { configure } = require('quasar/wrappers'); |
||||||
|
|
||||||
|
|
||||||
|
module.exports = configure(function (/* ctx */) { |
||||||
|
return { |
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/prefetch-feature
|
||||||
|
// preFetch: true,
|
||||||
|
|
||||||
|
// app boot file (/src/boot)
|
||||||
|
// --> boot files are part of "main.js"
|
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/boot-files
|
||||||
|
boot: [ |
||||||
|
|
||||||
|
'axios', |
||||||
|
], |
||||||
|
|
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
||||||
|
css: [ |
||||||
|
'app.scss' |
||||||
|
], |
||||||
|
|
||||||
|
// https://github.com/quasarframework/quasar/tree/dev/extras
|
||||||
|
extras: [ |
||||||
|
// 'ionicons-v4',
|
||||||
|
// 'mdi-v7',
|
||||||
|
// 'fontawesome-v6',
|
||||||
|
// 'eva-icons',
|
||||||
|
// 'themify',
|
||||||
|
// 'line-awesome',
|
||||||
|
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||||
|
|
||||||
|
'roboto-font', // optional, you are not bound to it
|
||||||
|
'material-icons', // optional, you are not bound to it
|
||||||
|
], |
||||||
|
|
||||||
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
|
||||||
|
build: { |
||||||
|
target: { |
||||||
|
browser: [ 'es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1' ], |
||||||
|
node: 'node20' |
||||||
|
}, |
||||||
|
|
||||||
|
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
||||||
|
// vueRouterBase,
|
||||||
|
// vueDevtools,
|
||||||
|
// vueOptionsAPI: false,
|
||||||
|
|
||||||
|
// rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
|
||||||
|
|
||||||
|
// publicPath: '/',
|
||||||
|
// analyze: true,
|
||||||
|
// env: {},
|
||||||
|
// rawDefine: {}
|
||||||
|
// ignorePublicFolder: true,
|
||||||
|
// minify: false,
|
||||||
|
// polyfillModulePreload: true,
|
||||||
|
// distDir
|
||||||
|
|
||||||
|
// extendViteConf (viteConf) {},
|
||||||
|
// viteVuePluginOptions: {},
|
||||||
|
|
||||||
|
vitePlugins: [ |
||||||
|
['vite-plugin-checker', { |
||||||
|
eslint: { |
||||||
|
lintCommand: 'eslint "./**/*.{js,mjs,cjs,vue}"' |
||||||
|
} |
||||||
|
}, { server: false }] |
||||||
|
] |
||||||
|
}, |
||||||
|
|
||||||
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
|
||||||
|
devServer: { |
||||||
|
// https: true
|
||||||
|
open: true // opens browser window automatically
|
||||||
|
}, |
||||||
|
|
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
||||||
|
framework: { |
||||||
|
config: {}, |
||||||
|
|
||||||
|
// iconSet: 'material-icons', // Quasar icon set
|
||||||
|
// lang: 'en-US', // Quasar language pack
|
||||||
|
|
||||||
|
// For special cases outside of where the auto-import strategy can have an impact
|
||||||
|
// (like functional components as one of the examples),
|
||||||
|
// you can manually specify Quasar components/directives to be available everywhere:
|
||||||
|
//
|
||||||
|
// components: [],
|
||||||
|
// directives: [],
|
||||||
|
|
||||||
|
// Quasar plugins
|
||||||
|
plugins: [] |
||||||
|
}, |
||||||
|
|
||||||
|
// animations: 'all', // --- includes all animations
|
||||||
|
// https://v2.quasar.dev/options/animations
|
||||||
|
animations: [], |
||||||
|
|
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles
|
||||||
|
// sourceFiles: {
|
||||||
|
// rootComponent: 'src/App.vue',
|
||||||
|
// router: 'src/router/index',
|
||||||
|
// store: 'src/store/index',
|
||||||
|
// registerServiceWorker: 'src-pwa/register-service-worker',
|
||||||
|
// serviceWorker: 'src-pwa/custom-service-worker',
|
||||||
|
// pwaManifestFile: 'src-pwa/manifest.json',
|
||||||
|
// electronMain: 'src-electron/electron-main',
|
||||||
|
// electronPreload: 'src-electron/electron-preload'
|
||||||
|
// },
|
||||||
|
|
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr
|
||||||
|
ssr: { |
||||||
|
// ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
|
||||||
|
// will mess up SSR
|
||||||
|
|
||||||
|
// extendSSRWebserverConf (esbuildConf) {},
|
||||||
|
// extendPackageJson (json) {},
|
||||||
|
|
||||||
|
pwa: false, |
||||||
|
|
||||||
|
// manualStoreHydration: true,
|
||||||
|
// manualPostHydrationTrigger: true,
|
||||||
|
|
||||||
|
prodPort: 3000, // The default port that the production server should use
|
||||||
|
// (gets superseded if process.env.PORT is specified at runtime)
|
||||||
|
|
||||||
|
middlewares: [ |
||||||
|
'render' // keep this as last one
|
||||||
|
] |
||||||
|
}, |
||||||
|
|
||||||
|
// https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa
|
||||||
|
pwa: { |
||||||
|
workboxMode: 'generateSW', // or 'injectManifest'
|
||||||
|
injectPwaMetaTags: true, |
||||||
|
swFilename: 'sw.js', |
||||||
|
manifestFilename: 'manifest.json', |
||||||
|
useCredentialsForManifestTag: false, |
||||||
|
// useFilenameHashes: true,
|
||||||
|
// extendGenerateSWOptions (cfg) {}
|
||||||
|
// extendInjectManifestOptions (cfg) {},
|
||||||
|
// extendManifestJson (json) {}
|
||||||
|
// extendPWACustomSWConf (esbuildConf) {}
|
||||||
|
}, |
||||||
|
|
||||||
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova
|
||||||
|
cordova: { |
||||||
|
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
|
||||||
|
}, |
||||||
|
|
||||||
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor
|
||||||
|
capacitor: { |
||||||
|
hideSplashscreen: true |
||||||
|
}, |
||||||
|
|
||||||
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron
|
||||||
|
electron: { |
||||||
|
// extendElectronMainConf (esbuildConf)
|
||||||
|
// extendElectronPreloadConf (esbuildConf)
|
||||||
|
|
||||||
|
// specify the debugging port to use for the Electron app when running in development mode
|
||||||
|
inspectPort: 5858, |
||||||
|
|
||||||
|
bundler: 'packager', // 'packager' or 'builder'
|
||||||
|
|
||||||
|
packager: { |
||||||
|
// https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
|
||||||
|
|
||||||
|
// OS X / Mac App Store
|
||||||
|
// appBundleId: '',
|
||||||
|
// appCategoryType: '',
|
||||||
|
// osxSign: '',
|
||||||
|
// protocol: 'myapp://path',
|
||||||
|
|
||||||
|
// Windows only
|
||||||
|
// win32metadata: { ... }
|
||||||
|
}, |
||||||
|
|
||||||
|
builder: { |
||||||
|
// https://www.electron.build/configuration/configuration
|
||||||
|
|
||||||
|
appId: 'rition-panel' |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
|
||||||
|
bex: { |
||||||
|
contentScripts: [ |
||||||
|
'my-content-script' |
||||||
|
], |
||||||
|
|
||||||
|
// extendBexScriptsConf (esbuildConf) {}
|
||||||
|
// extendBexManifestJson (json) {}
|
||||||
|
} |
||||||
|
} |
||||||
|
}); |
@ -1,30 +1,9 @@ |
|||||||
<script setup> |
|
||||||
import HelloWorld from './components/HelloWorld.vue' |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
<template> |
||||||
<div> |
<router-view /> |
||||||
<a href="https://vitejs.dev" target="_blank"> |
|
||||||
<img src="/vite.svg" class="logo" alt="Vite logo" /> |
|
||||||
</a> |
|
||||||
<a href="https://vuejs.org/" target="_blank"> |
|
||||||
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" /> |
|
||||||
</a> |
|
||||||
</div> |
|
||||||
<HelloWorld msg="Vite + Vue" /> |
|
||||||
</template> |
</template> |
||||||
|
|
||||||
<style scoped> |
<script setup> |
||||||
.logo { |
defineOptions({ |
||||||
height: 6em; |
name: 'App' |
||||||
padding: 1.5em; |
}); |
||||||
will-change: filter; |
</script> |
||||||
transition: filter 300ms; |
|
||||||
} |
|
||||||
.logo:hover { |
|
||||||
filter: drop-shadow(0 0 2em #646cffaa); |
|
||||||
} |
|
||||||
.logo.vue:hover { |
|
||||||
filter: drop-shadow(0 0 2em #42b883aa); |
|
||||||
} |
|
||||||
</style> |
|
||||||
|
After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 496 B |
@ -0,0 +1,24 @@ |
|||||||
|
import { boot } from 'quasar/wrappers' |
||||||
|
import axios from 'axios' |
||||||
|
|
||||||
|
// Be careful when using SSR for cross-request state pollution
|
||||||
|
// due to creating a Singleton instance here;
|
||||||
|
// If any client changes this (global) instance, it might be a
|
||||||
|
// good idea to move this instance creation inside of the
|
||||||
|
// "export default () => {}" function below (which runs individually
|
||||||
|
// for each client)
|
||||||
|
const api = axios.create({ baseURL: 'https://api.example.com' }) |
||||||
|
|
||||||
|
export default boot(({ app }) => { |
||||||
|
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||||
|
|
||||||
|
app.config.globalProperties.$axios = axios |
||||||
|
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
|
||||||
|
// so you won't necessarily have to import axios in each vue file
|
||||||
|
|
||||||
|
app.config.globalProperties.$api = api |
||||||
|
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
|
||||||
|
// so you can easily perform requests against your app's API
|
||||||
|
}) |
||||||
|
|
||||||
|
export { api } |
@ -0,0 +1,48 @@ |
|||||||
|
<template> |
||||||
|
<q-item |
||||||
|
clickable |
||||||
|
tag="a" |
||||||
|
target="_blank" |
||||||
|
:href="props.link" |
||||||
|
> |
||||||
|
<q-item-section |
||||||
|
v-if="props.icon" |
||||||
|
avatar |
||||||
|
> |
||||||
|
<q-icon :name="props.icon" /> |
||||||
|
</q-item-section> |
||||||
|
|
||||||
|
<q-item-section> |
||||||
|
<q-item-label>{{ props.title }}</q-item-label> |
||||||
|
<q-item-label caption>{{ props.caption }}</q-item-label> |
||||||
|
</q-item-section> |
||||||
|
</q-item> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup> |
||||||
|
defineOptions({ |
||||||
|
name: 'EssentialLink' |
||||||
|
}) |
||||||
|
|
||||||
|
const props = defineProps({ |
||||||
|
title: { |
||||||
|
type: String, |
||||||
|
required: true |
||||||
|
}, |
||||||
|
|
||||||
|
caption: { |
||||||
|
type: String, |
||||||
|
default: '' |
||||||
|
}, |
||||||
|
|
||||||
|
link: { |
||||||
|
type: String, |
||||||
|
default: '#' |
||||||
|
}, |
||||||
|
|
||||||
|
icon: { |
||||||
|
type: String, |
||||||
|
default: '' |
||||||
|
} |
||||||
|
}) |
||||||
|
</script> |
@ -1,40 +0,0 @@ |
|||||||
<script setup> |
|
||||||
import { ref } from 'vue' |
|
||||||
|
|
||||||
defineProps({ |
|
||||||
msg: String, |
|
||||||
}) |
|
||||||
|
|
||||||
const count = ref(0) |
|
||||||
</script> |
|
||||||
|
|
||||||
<template> |
|
||||||
<h1>{{ msg }}</h1> |
|
||||||
|
|
||||||
<div class="card"> |
|
||||||
<button type="button" @click="count++">count is {{ count }}</button> |
|
||||||
<p> |
|
||||||
Edit |
|
||||||
<code>components/HelloWorld.vue</code> to test HMR |
|
||||||
</p> |
|
||||||
</div> |
|
||||||
|
|
||||||
<p> |
|
||||||
Check out |
|
||||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank" |
|
||||||
>create-vue</a |
|
||||||
>, the official Vue + Vite starter |
|
||||||
</p> |
|
||||||
<p> |
|
||||||
Install |
|
||||||
<a href="https://github.com/vuejs/language-tools" target="_blank">Volar</a> |
|
||||||
in your IDE for a better DX |
|
||||||
</p> |
|
||||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p> |
|
||||||
</template> |
|
||||||
|
|
||||||
<style scoped> |
|
||||||
.read-the-docs { |
|
||||||
color: #888; |
|
||||||
} |
|
||||||
</style> |
|
@ -0,0 +1 @@ |
|||||||
|
// app global css in SCSS form |
@ -0,0 +1,25 @@ |
|||||||
|
// Quasar SCSS (& Sass) Variables |
||||||
|
// -------------------------------------------------- |
||||||
|
// To customize the look and feel of this app, you can override |
||||||
|
// the Sass/SCSS variables found in Quasar's source Sass/SCSS files. |
||||||
|
|
||||||
|
// Check documentation for full list of Quasar variables |
||||||
|
|
||||||
|
// Your own variables (that are declared here) and Quasar's own |
||||||
|
// ones will be available out of the box in your .vue/.scss/.sass files |
||||||
|
|
||||||
|
// It's highly recommended to change the default colors |
||||||
|
// to match your app's branding. |
||||||
|
// Tip: Use the "Theme Builder" on Quasar's documentation website. |
||||||
|
|
||||||
|
$primary : #1976D2; |
||||||
|
$secondary : #26A69A; |
||||||
|
$accent : #9C27B0; |
||||||
|
|
||||||
|
$dark : #1D1D1D; |
||||||
|
$dark-page : #121212; |
||||||
|
|
||||||
|
$positive : #21BA45; |
||||||
|
$negative : #C10015; |
||||||
|
$info : #31CCEC; |
||||||
|
$warning : #F2C037; |
@ -0,0 +1,106 @@ |
|||||||
|
<template> |
||||||
|
<q-layout view="lHh Lpr lFf"> |
||||||
|
<q-header elevated> |
||||||
|
<q-toolbar> |
||||||
|
<q-btn |
||||||
|
flat |
||||||
|
dense |
||||||
|
round |
||||||
|
icon="menu" |
||||||
|
aria-label="Menu" |
||||||
|
@click="toggleLeftDrawer" |
||||||
|
/> |
||||||
|
|
||||||
|
<q-toolbar-title> |
||||||
|
Quasar App |
||||||
|
</q-toolbar-title> |
||||||
|
|
||||||
|
<div>Quasar v{{ $q.version }}</div> |
||||||
|
</q-toolbar> |
||||||
|
</q-header> |
||||||
|
|
||||||
|
<q-drawer |
||||||
|
v-model="leftDrawerOpen" |
||||||
|
show-if-above |
||||||
|
bordered |
||||||
|
> |
||||||
|
<q-list> |
||||||
|
<q-item-label |
||||||
|
header |
||||||
|
> |
||||||
|
Essential Links |
||||||
|
</q-item-label> |
||||||
|
|
||||||
|
<EssentialLink |
||||||
|
v-for="link in linksList" |
||||||
|
:key="link.title" |
||||||
|
v-bind="link" |
||||||
|
/> |
||||||
|
</q-list> |
||||||
|
</q-drawer> |
||||||
|
|
||||||
|
<q-page-container> |
||||||
|
<router-view /> |
||||||
|
</q-page-container> |
||||||
|
</q-layout> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup> |
||||||
|
import { ref } from 'vue' |
||||||
|
import EssentialLink from 'components/EssentialLink.vue' |
||||||
|
|
||||||
|
defineOptions({ |
||||||
|
name: 'MainLayout' |
||||||
|
}) |
||||||
|
|
||||||
|
const linksList = [ |
||||||
|
{ |
||||||
|
title: 'Docs', |
||||||
|
caption: 'quasar.dev', |
||||||
|
icon: 'school', |
||||||
|
link: 'https://quasar.dev' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Github', |
||||||
|
caption: 'github.com/quasarframework', |
||||||
|
icon: 'code', |
||||||
|
link: 'https://github.com/quasarframework' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Discord Chat Channel', |
||||||
|
caption: 'chat.quasar.dev', |
||||||
|
icon: 'chat', |
||||||
|
link: 'https://chat.quasar.dev' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Forum', |
||||||
|
caption: 'forum.quasar.dev', |
||||||
|
icon: 'record_voice_over', |
||||||
|
link: 'https://forum.quasar.dev' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Twitter', |
||||||
|
caption: '@quasarframework', |
||||||
|
icon: 'rss_feed', |
||||||
|
link: 'https://twitter.quasar.dev' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Facebook', |
||||||
|
caption: '@QuasarFramework', |
||||||
|
icon: 'public', |
||||||
|
link: 'https://facebook.quasar.dev' |
||||||
|
}, |
||||||
|
{ |
||||||
|
title: 'Quasar Awesome', |
||||||
|
caption: 'Community Quasar projects', |
||||||
|
icon: 'favorite', |
||||||
|
link: 'https://awesome.quasar.dev' |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
const leftDrawerOpen = ref(false) |
||||||
|
|
||||||
|
function toggleLeftDrawer () { |
||||||
|
leftDrawerOpen.value = !leftDrawerOpen.value |
||||||
|
} |
||||||
|
</script> |
@ -1,5 +0,0 @@ |
|||||||
import { createApp } from 'vue' |
|
||||||
import './style.css' |
|
||||||
import App from './App.vue' |
|
||||||
|
|
||||||
createApp(App).mount('#app') |
|
@ -0,0 +1,29 @@ |
|||||||
|
<template> |
||||||
|
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center"> |
||||||
|
<div> |
||||||
|
<div style="font-size: 30vh"> |
||||||
|
404 |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="text-h2" style="opacity:.4"> |
||||||
|
Oops. Nothing here... |
||||||
|
</div> |
||||||
|
|
||||||
|
<q-btn |
||||||
|
class="q-mt-xl" |
||||||
|
color="white" |
||||||
|
text-color="blue" |
||||||
|
unelevated |
||||||
|
to="/" |
||||||
|
label="Go Home" |
||||||
|
no-caps |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup> |
||||||
|
defineOptions({ |
||||||
|
name: 'ErrorNotFound' |
||||||
|
}); |
||||||
|
</script> |
@ -0,0 +1,15 @@ |
|||||||
|
<template> |
||||||
|
<q-page class="flex flex-center"> |
||||||
|
<img |
||||||
|
alt="Quasar logo" |
||||||
|
src="~assets/quasar-logo-vertical.svg" |
||||||
|
style="width: 200px; height: 200px" |
||||||
|
> |
||||||
|
</q-page> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup> |
||||||
|
defineOptions({ |
||||||
|
name: 'IndexPage' |
||||||
|
}); |
||||||
|
</script> |
@ -0,0 +1,30 @@ |
|||||||
|
import { route } from 'quasar/wrappers' |
||||||
|
import { createRouter, createMemoryHistory, createWebHistory, createWebHashHistory } from 'vue-router' |
||||||
|
import routes from './routes' |
||||||
|
|
||||||
|
/* |
||||||
|
* If not building with SSR mode, you can |
||||||
|
* directly export the Router instantiation; |
||||||
|
* |
||||||
|
* The function below can be async too; either use |
||||||
|
* async/await or return a Promise which resolves |
||||||
|
* with the Router instance. |
||||||
|
*/ |
||||||
|
|
||||||
|
export default route(function (/* { store, ssrContext } */) { |
||||||
|
const createHistory = process.env.SERVER |
||||||
|
? createMemoryHistory |
||||||
|
: (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory) |
||||||
|
|
||||||
|
const Router = createRouter({ |
||||||
|
scrollBehavior: () => ({ left: 0, top: 0 }), |
||||||
|
routes, |
||||||
|
|
||||||
|
// Leave this as is and make changes in quasar.conf.js instead!
|
||||||
|
// quasar.conf.js -> build -> vueRouterMode
|
||||||
|
// quasar.conf.js -> build -> publicPath
|
||||||
|
history: createHistory(process.env.VUE_ROUTER_BASE) |
||||||
|
}) |
||||||
|
|
||||||
|
return Router |
||||||
|
}) |
@ -0,0 +1,18 @@ |
|||||||
|
const routes = [ |
||||||
|
{ |
||||||
|
path: '/', |
||||||
|
component: () => import('layouts/MainLayout.vue'), |
||||||
|
children: [ |
||||||
|
{ path: '', component: () => import('pages/IndexPage.vue') } |
||||||
|
] |
||||||
|
}, |
||||||
|
|
||||||
|
// Always leave this as last one,
|
||||||
|
// but you can also remove it
|
||||||
|
{ |
||||||
|
path: '/:catchAll(.*)*', |
||||||
|
component: () => import('pages/ErrorNotFound.vue') |
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
export default routes |
@ -1,79 +0,0 @@ |
|||||||
:root { |
|
||||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; |
|
||||||
line-height: 1.5; |
|
||||||
font-weight: 400; |
|
||||||
|
|
||||||
color-scheme: light dark; |
|
||||||
color: rgba(255, 255, 255, 0.87); |
|
||||||
background-color: #242424; |
|
||||||
|
|
||||||
font-synthesis: none; |
|
||||||
text-rendering: optimizeLegibility; |
|
||||||
-webkit-font-smoothing: antialiased; |
|
||||||
-moz-osx-font-smoothing: grayscale; |
|
||||||
} |
|
||||||
|
|
||||||
a { |
|
||||||
font-weight: 500; |
|
||||||
color: #646cff; |
|
||||||
text-decoration: inherit; |
|
||||||
} |
|
||||||
a:hover { |
|
||||||
color: #535bf2; |
|
||||||
} |
|
||||||
|
|
||||||
body { |
|
||||||
margin: 0; |
|
||||||
display: flex; |
|
||||||
place-items: center; |
|
||||||
min-width: 320px; |
|
||||||
min-height: 100vh; |
|
||||||
} |
|
||||||
|
|
||||||
h1 { |
|
||||||
font-size: 3.2em; |
|
||||||
line-height: 1.1; |
|
||||||
} |
|
||||||
|
|
||||||
button { |
|
||||||
border-radius: 8px; |
|
||||||
border: 1px solid transparent; |
|
||||||
padding: 0.6em 1.2em; |
|
||||||
font-size: 1em; |
|
||||||
font-weight: 500; |
|
||||||
font-family: inherit; |
|
||||||
background-color: #1a1a1a; |
|
||||||
cursor: pointer; |
|
||||||
transition: border-color 0.25s; |
|
||||||
} |
|
||||||
button:hover { |
|
||||||
border-color: #646cff; |
|
||||||
} |
|
||||||
button:focus, |
|
||||||
button:focus-visible { |
|
||||||
outline: 4px auto -webkit-focus-ring-color; |
|
||||||
} |
|
||||||
|
|
||||||
.card { |
|
||||||
padding: 2em; |
|
||||||
} |
|
||||||
|
|
||||||
#app { |
|
||||||
max-width: 1280px; |
|
||||||
margin: 0 auto; |
|
||||||
padding: 2rem; |
|
||||||
text-align: center; |
|
||||||
} |
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) { |
|
||||||
:root { |
|
||||||
color: #213547; |
|
||||||
background-color: #ffffff; |
|
||||||
} |
|
||||||
a:hover { |
|
||||||
color: #747bff; |
|
||||||
} |
|
||||||
button { |
|
||||||
background-color: #f9f9f9; |
|
||||||
} |
|
||||||
} |
|
@ -1,7 +0,0 @@ |
|||||||
import { defineConfig } from 'vite' |
|
||||||
import vue from '@vitejs/plugin-vue' |
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig({ |
|
||||||
plugins: [vue()], |
|
||||||
}) |
|
@ -0,0 +1,15 @@ |
|||||||
|
package client |
||||||
|
|
||||||
|
type Config struct { |
||||||
|
CenterServer string `json:"centerServer,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
type Client struct { |
||||||
|
config Config |
||||||
|
} |
||||||
|
|
||||||
|
func NetClient(config Config) *Client { |
||||||
|
return &Client{ |
||||||
|
config: config, |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package client |
||||||
|
|
||||||
|
import ( |
||||||
|
"bytes" |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"net/http" |
||||||
|
) |
||||||
|
|
||||||
|
type DataItem struct { |
||||||
|
Metric string `json:"metric"` |
||||||
|
Tags map[string]string `json:"tags"` |
||||||
|
Timestamp int64 `json:"timestamp"` |
||||||
|
Value any `json:"value"` |
||||||
|
} |
||||||
|
|
||||||
|
type ReportResponse struct { |
||||||
|
RequestId string `json:"request_id,omitempty"` |
||||||
|
Message string `json:"message,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
func (c *Client) Report(dataItem []DataItem) (*ReportResponse, error) { |
||||||
|
reportJsonBytes, err := json.Marshal(dataItem) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// send report data
|
||||||
|
resp, err := http.Post(c.config.CenterServer, "application/json", bytes.NewBuffer(reportJsonBytes)) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// get response
|
||||||
|
defer func(Body io.ReadCloser) { |
||||||
|
_ = Body.Close() |
||||||
|
}(resp.Body) |
||||||
|
|
||||||
|
respBytes, err := io.ReadAll(resp.Body) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
fmt.Println(string(respBytes)) |
||||||
|
|
||||||
|
response := ReportResponse{} |
||||||
|
err = json.Unmarshal(respBytes, &response) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return &response, nil |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
module rition-testsuite |
||||||
|
|
||||||
|
go 1.22.0 |
||||||
|
|
||||||
|
require github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect |
@ -0,0 +1,2 @@ |
|||||||
|
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU= |
||||||
|
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A= |
@ -0,0 +1,28 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"flag" |
||||||
|
"rition-testsuite/client" |
||||||
|
"rition-testsuite/service" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
// --report '127.0.0.1:22019' --disk_dev nvme0n1 --mount / --net_dev wlp0s20f3 --interval 30
|
||||||
|
centerServer := flag.String("report", "http://localhost:8000/api/metric/put", "上报中心") |
||||||
|
interval := flag.Int("interval", 5, "上报间隔,单位为秒") |
||||||
|
dataFile := flag.String("data", "./data/abnormal_data_22000_500_171.json", "数据文件") |
||||||
|
flag.Parse() |
||||||
|
|
||||||
|
config := service.Config{ |
||||||
|
ClientConfig: client.Config{ |
||||||
|
CenterServer: *centerServer, |
||||||
|
}, |
||||||
|
ReportInterval: time.Duration(*interval) * time.Second, |
||||||
|
DataFileLocation: *dataFile, |
||||||
|
} |
||||||
|
|
||||||
|
srv := service.NewService(config) |
||||||
|
srv.Run() |
||||||
|
//srv.Report()
|
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
package service |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"fmt" |
||||||
|
"github.com/emirpasic/gods/v2/sets/hashset" |
||||||
|
"os" |
||||||
|
"rition-testsuite/client" |
||||||
|
"sort" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
func (s *Service) Run() { |
||||||
|
data, err := os.ReadFile(s.config.DataFileLocation) |
||||||
|
if err != nil { |
||||||
|
fmt.Println(err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
fileDataItemList := make([]client.DataItem, 0) |
||||||
|
err = json.Unmarshal(data, &fileDataItemList) |
||||||
|
if err != nil { |
||||||
|
fmt.Println(err.Error()) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
sort.Slice(fileDataItemList, func(i, j int) bool { |
||||||
|
return fileDataItemList[i].Timestamp < fileDataItemList[j].Timestamp |
||||||
|
}) |
||||||
|
|
||||||
|
times := hashset.New[int64]() |
||||||
|
fileDataMap := map[int64][]client.DataItem{} |
||||||
|
for _, dataItem := range fileDataItemList { |
||||||
|
if _, has := fileDataMap[dataItem.Timestamp]; !has { |
||||||
|
fileDataMap[dataItem.Timestamp] = make([]client.DataItem, 0, 22) |
||||||
|
} |
||||||
|
|
||||||
|
fileDataMap[dataItem.Timestamp] = append(fileDataMap[dataItem.Timestamp], dataItem) |
||||||
|
times.Add(dataItem.Timestamp) |
||||||
|
} |
||||||
|
|
||||||
|
i := 0 |
||||||
|
timesValue := times.Values() |
||||||
|
sort.Slice(timesValue, func(i, j int) bool { |
||||||
|
return timesValue[i] < timesValue[j] |
||||||
|
}) |
||||||
|
|
||||||
|
fileDataItemList = nil |
||||||
|
times = nil |
||||||
|
|
||||||
|
ticker := time.NewTicker(s.config.ReportInterval) |
||||||
|
defer ticker.Stop() |
||||||
|
for range ticker.C { |
||||||
|
if i < len(timesValue) { |
||||||
|
fmt.Printf("reporting: %d\n", timesValue[i]) |
||||||
|
s.Report(fileDataMap[timesValue[i]]) |
||||||
|
i++ |
||||||
|
} else { |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (s *Service) Report(dataList []client.DataItem) { |
||||||
|
_, err := s.client.Report(dataList) |
||||||
|
if err != nil { |
||||||
|
fmt.Println("err: ", err.Error()) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package service |
||||||
|
|
||||||
|
import ( |
||||||
|
"rition-testsuite/client" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
type Config struct { |
||||||
|
ClientConfig client.Config |
||||||
|
DataFileLocation string |
||||||
|
|
||||||
|
ReportInterval time.Duration `json:"reportInterval,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
type Service struct { |
||||||
|
config Config |
||||||
|
client *client.Client |
||||||
|
} |
||||||
|
|
||||||
|
func NewService(config Config) *Service { |
||||||
|
service := Service{ |
||||||
|
config: config, |
||||||
|
client: client.NetClient(config.ClientConfig), |
||||||
|
} |
||||||
|
|
||||||
|
return &service |
||||||
|
} |