Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Converter #1

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/logo.png"/>
<link rel="icon" type="image/png" href="/logo.png"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>UIGF Schema Verify Tool</title>
<title>UIGF Tools</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
},
"dependencies": {
"ajv": "^8.13.0",
"vue": "^3.4.27"
"vue": "^3.4.27",
"vue-router": "^4.4.0"
},
"devDependencies": {
"@arco-design/web-vue": "^2.55.2",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue": "^5.0.5",
"typescript": "^5.4.5",
"vite": "^5.2.11",
"vite": "^5.3.3",
"vue-tsc": "^2.0.17"
}
}
342 changes: 234 additions & 108 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

240 changes: 9 additions & 231 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,237 +1,15 @@
<template>
<div class="app-container">
<div class="app-title">
<img src="/logo.png" alt="logo"/>
<span>UIGF Schema Verify Tool</span>
<a-upload :show-file-list="false" :custom-request="uploadFile"></a-upload>
<a-button type="primary" @click="verify()">验证</a-button>
<a-select v-model="curSchema" style="width: 100px">
<a-option :value="SchemaType.UIGF">{{ SchemaType.UIGF.toUpperCase() }}</a-option>
<a-option :value="SchemaType.UIAF">{{ SchemaType.UIAF.toUpperCase() }}</a-option>
<a-option :value="SchemaType.SRGF">{{ SchemaType.SRGF.toUpperCase() }}</a-option>
</a-select>
</div>
<div class="verify-result" v-if="verifyResult !== ''">
<a-alert type="success" v-if="isSucceed">Verification passed</a-alert>
<a-alert type="error" v-else>
<span v-if="typeof verifyResult === 'string'">{{ verifyResult }}</span>
<ul v-else>
<li v-for="error in verifyResult" :key="error.instancePath">
<span class="error-path">{{ error.instancePath || error.schemaPath }}:&emsp;</span>
<span class="error-message">{{ error.message }}</span>
<span style="margin-left: auto" v-if="error.instancePath!==''">
<a-button @click="showErrData(error)" type="text">查看错误数据</a-button>
</span>
</li>
</ul>
</a-alert>
</div>
<div class="verify-body">
<div class="verify-item">
<div class="verify-title">File Content</div>
<a-textarea class="verify-box" v-model="fileContent" readonly auto-size/>
</div>
<div class="verify-item">
<div class="verify-title">
<span>Schema</span>
</div>
<a-textarea class="verify-box" :model-value="JSON.stringify(schema, null, 2)" readonly auto-size/>
</div>
</div>
</div>
<div id="app">
<router-view></router-view>
</div>
</template>

<script setup lang="ts">
import Ajv, {ErrorObject, ValidateFunction} from "ajv";
import {computed, onMounted, ref, watch} from "vue";
import {RequestOption, UploadRequest} from "@arco-design/web-vue";
import {getSchema, SchemaType} from "./tools/schemaSwitch.ts";

const ajv = new Ajv();

const validate = ref<ValidateFunction | undefined>(undefined);

// 当前schema类型
const curSchema = ref<SchemaType>(SchemaType.UIGF);

onMounted(async () => {
const url = new URL(window.location.href);
const schemaType = url.searchParams.get("schema");
const check = [SchemaType.UIGF, SchemaType.UIAF, SchemaType.SRGF];
if (check.includes(schemaType as SchemaType)) {
curSchema.value = schemaType as SchemaType;
}
await freshSchema(curSchema.value);
});

// freshSchema
async function freshSchema(schemaType: SchemaType = curSchema.value) {
schema.value = await getSchema(schemaType);
validate.value = ajv.compile(schema.value);
}

// 监听schema类型变化
watch(curSchema, async (value: SchemaType) => await freshSchema(value));

// schema 文件内容
const schema = ref<any>({});
// 文件内容
const fileContent = ref<string>("");
// 验证结果
const verifyResult = ref<string | Array<ErrorObject>>("");
// 是否验证成功
const isSucceed = computed(() => {
if (verifyResult.value === "Verification passed") {
return true;
}
if (verifyResult.value === "Verification failed") {
return false;
}
return !verifyResult.value.length;
})

// 上传文件
function uploadFile(option: RequestOption): UploadRequest {
const file = option.fileItem.file;
if (!file) {
option.onError();
return {};
}
const reader = new FileReader();
try {
reader.onload = (e) => {
fileContent.value = e.target?.result as string;
verify();
};
reader.readAsText(file);
option.onSuccess();
} catch (e) {
option.onError();
}
return {};
}

// 验证
function verify() {
if (validate.value === undefined) {
console.error("Schema is not loaded");
return;
}
try {
const data = JSON.parse(fileContent.value);
const valid = validate.value(data);
if (valid) {
verifyResult.value = "Verification passed";
return;
}
verifyResult.value = validate.value.errors || "Verification failed";
console.log(validate.value.errors);
} catch (e) {
verifyResult.value = "Verification failed\n" + e;
}
}

// 显示错误数据
function showErrData(error: ErrorObject) {
const path = error.instancePath.split("/").filter((item) => item);
let data = JSON.parse(fileContent.value);
// 最多深入两层
for (let i = 0; i < Math.min(path.length, 2); i++) {
data = data[path[i]];
}
alert(JSON.stringify(data, null, 2));
}
<script lang="js">
export default {
name: 'App',
};
</script>


<style lang="css" scoped>
.app-container {
position: relative;
margin: 20px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 20px;
}

.app-title {
display: flex;
align-items: center;
justify-content: flex-start;
column-gap: 10px;
flex-wrap: wrap;
}

.app-title img {
width: 40px;
height: 40px;
}

.app-title span {
font-size: 20px;
font-weight: bold;
}

.verify-body {
position: relative;
display: flex;
width: 100%;
justify-content: space-between;
}

@media (max-width: 768px) {
.verify-body {
flex-direction: column;
}

.verify-body > .verify-item {
width: 100%;
}
}

.verify-item {
width: 49%;
}

.verify-title {
font-size: 16px;
font-weight: bold;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: flex-start;
column-gap: 10px;
}

.verify-box {
width: 100%;
height: calc(100vh - 200px);
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
overflow-y: auto;
}

.verify-result {
width: 100%;
}

.verify-result ul {
list-style: none;
padding: 0;
}

.verify-result li {
margin-top: 10px;
}

.error-path {
font-weight: bold;
color: #D14748;
}

.error-message {
color: #EC407A;
}
<style>
/* 你的样式 */
</style>
15 changes: 15 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createApp } from 'vue';
import App from './App.vue';
import ArcoVue from '@arco-design/web-vue';
import { Message } from '@arco-design/web-vue';
import '@arco-design/web-vue/dist/arco.css';
import router from './router';

const app = createApp(App);

app.use(router);
app.use(ArcoVue);
app.mount('#app');

Message._context = app._context;

6 changes: 0 additions & 6 deletions src/main.ts

This file was deleted.

27 changes: 27 additions & 0 deletions src/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createRouter, createWebHistory } from 'vue-router';
import verify from '@/views/verify.vue';
import conversion from '@/views/conversion.vue';

const routes = [
{
path: '/',
redirect: 'Conv'
},
{
path: '/verify',
name: 'Verify',
component: verify,
},
{
path: '/conv',
name: 'Conv',
component: conversion
}
];

const router = createRouter({
history: createWebHistory(),
routes,
});

export default router;
File renamed without changes.
Loading