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 | ||||||
|  | } | ||||||