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; | ||||
| 
 | ||||
| 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 { | ||||
| 
 | ||||
|     @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 | ||||
| logs | ||||
| *.log | ||||
| .DS_Store | ||||
| .thumbs.db | ||||
| 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* | ||||
| yarn-debug.log* | ||||
| yarn-error.log* | ||||
| pnpm-debug.log* | ||||
| lerna-debug.log* | ||||
| 
 | ||||
| node_modules | ||||
| dist | ||||
| dist-ssr | ||||
| *.local | ||||
| 
 | ||||
| # Editor directories and files | ||||
| .vscode/* | ||||
| !.vscode/extensions.json | ||||
| .idea | ||||
| .DS_Store | ||||
| *.suo | ||||
| *.ntvs* | ||||
| *.njsproj | ||||
| *.sln | ||||
| *.sw? | ||||
| 
 | ||||
| # 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> | ||||
| <html lang="en"> | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|   <head> | ||||
|     <meta charset="UTF-8" /> | ||||
|     <link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
|     <title>Vite + Vue</title> | ||||
|     <title><%= productName %></title> | ||||
| 
 | ||||
|     <meta charset="utf-8"> | ||||
|     <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> | ||||
|   <body> | ||||
|     <div id="app"></div> | ||||
|     <script type="module" src="/src/main.js"></script> | ||||
|     <!-- quasar:entry-point --> | ||||
|   </body> | ||||
| </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", | ||||
|   "version": "0.0.1", | ||||
|   "description": "Panel of Rition project", | ||||
|   "productName": "RitionPanel", | ||||
|   "author": "lensfrex <lensferno@outlook.com>", | ||||
|   "private": true, | ||||
|   "version": "0.0.0", | ||||
|   "type": "module", | ||||
|   "scripts": { | ||||
|     "dev": "vite", | ||||
|     "build": "vite build", | ||||
|     "preview": "vite preview" | ||||
|     "lint": "eslint --ext .js,.vue ./", | ||||
|     "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore", | ||||
|     "test": "echo \"No test specified\" && exit 0", | ||||
|     "dev": "quasar dev", | ||||
|     "build": "quasar build" | ||||
|   }, | ||||
|   "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": { | ||||
|     "@vitejs/plugin-vue": "^5.0.4", | ||||
|     "vite": "^5.2.0" | ||||
|     "eslint": "^8.57.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> | ||||
|   <div> | ||||
|     <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" /> | ||||
|   <router-view /> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| .logo { | ||||
|   height: 6em; | ||||
|   padding: 1.5em; | ||||
|   will-change: filter; | ||||
|   transition: filter 300ms; | ||||
| } | ||||
| .logo:hover { | ||||
|   filter: drop-shadow(0 0 2em #646cffaa); | ||||
| } | ||||
| .logo.vue:hover { | ||||
|   filter: drop-shadow(0 0 2em #42b883aa); | ||||
| } | ||||
| </style> | ||||
| <script setup> | ||||
| defineOptions({ | ||||
|   name: 'App' | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| 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 | ||||
| } | ||||