Ly 1 month ago
commit 54f2a33f09
  1. 1
      .gitignore
  2. 1209
      package-lock.json
  3. 4
      package.json
  4. 23
      pnpm-lock.yaml
  5. 46
      src/api/index.ts
  6. 25
      src/api/user.ts
  7. BIN
      src/assets/images/idea.png
  8. 478
      src/layout/loginPage.vue
  9. 7
      src/main.ts
  10. 13
      src/permissions.ts
  11. 7
      src/router/index.ts
  12. 43
      src/store/modules/setting.ts
  13. 23
      src/store/modules/user.ts
  14. 12
      src/utils/index.ts
  15. 16
      src/utils/setStep.ts
  16. 77
      src/views/compiler/index.vue
  17. 35
      src/views/designRoute/components/wenBenYu.vue
  18. 10
      src/views/designRoute/components/wenBenYu2.vue
  19. 105
      src/views/designRoute/index.vue
  20. 8
      src/views/program/components/yibiao.vue
  21. 281
      src/views/program/index.vue
  22. 2
      tsconfig.json

1
.gitignore vendored

@ -9,6 +9,7 @@ lerna-debug.log*
pnpm-lock.yaml
node_modules
dist
package-lock.json
dist-ssr
*.local

1209
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -19,10 +19,12 @@
"@antv/x6-plugin-transform": "^2.1.8",
"@antv/x6-vue-shape": "^2.1.2",
"@element-plus/icons-vue": "^2.3.1",
"@highlightjs/vue-plugin": "^2.1.0",
"@kjgl77/datav-vue3": "^1.7.3",
"axios": "^1.7.2",
"echarts": "^5.6.0",
"element-plus": "^2.9.5",
"highlight.js": "^11.11.1",
"insert-css": "^2.0.0",
"lib-flexible": "^0.3.2",
"pinia": "^2.1.7",
@ -41,6 +43,8 @@
"postcss-scss": "^4.0.9",
"px2rem-loader": "^0.1.9",
"typescript": "^5.2.2",
"unplugin-auto-import": "^19.1.1",
"unplugin-vue-components": "^28.4.1",
"vite": "^5.3.1",
"vue-tsc": "^2.0.21"
}

@ -38,6 +38,9 @@ importers:
'@element-plus/icons-vue':
specifier: ^2.3.1
version: 2.3.1(vue@3.4.29(typescript@5.2.2))
'@highlightjs/vue-plugin':
specifier: ^2.1.0
version: 2.1.0(highlight.js@11.11.1)(vue@3.4.29(typescript@5.2.2))
'@kjgl77/datav-vue3':
specifier: ^1.7.3
version: 1.7.3(vue@3.4.29(typescript@5.2.2))
@ -50,6 +53,9 @@ importers:
element-plus:
specifier: ^2.9.5
version: 2.9.5(vue@3.4.29(typescript@5.2.2))
highlight.js:
specifier: ^11.11.1
version: 11.11.1
insert-css:
specifier: ^2.0.0
version: 2.0.0
@ -344,6 +350,12 @@ packages:
'@floating-ui/utils@0.2.9':
resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==}
'@highlightjs/vue-plugin@2.1.0':
resolution: {integrity: sha512-E+bmk4ncca+hBEYRV2a+1aIzIV0VSY/e5ArjpuSN9IO7wBJrzUE2u4ESCwrbQD7sAy+jWQjkV5qCCWgc+pu7CQ==}
peerDependencies:
highlight.js: ^11.0.1
vue: ^3
'@jiaminghi/bezier-curve@0.0.9':
resolution: {integrity: sha512-u9xJPOEl6Dri2E9FfmJoGxYQY7vYJkURNX04Vj64tdi535tPrpkuf9Sm0lNr3QTKdHQh0DdNRsaa62FLQNQEEw==}
@ -772,6 +784,10 @@ packages:
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
hasBin: true
highlight.js@11.11.1:
resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==}
engines: {node: '>=12.0.0'}
htmlparser2@8.0.2:
resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==}
@ -1362,6 +1378,11 @@ snapshots:
'@floating-ui/utils@0.2.9': {}
'@highlightjs/vue-plugin@2.1.0(highlight.js@11.11.1)(vue@3.4.29(typescript@5.2.2))':
dependencies:
highlight.js: 11.11.1
vue: 3.4.29(typescript@5.2.2)
'@jiaminghi/bezier-curve@0.0.9':
dependencies:
'@babel/runtime': 7.24.7
@ -1847,6 +1868,8 @@ snapshots:
he@1.2.0: {}
highlight.js@11.11.1: {}
htmlparser2@8.0.2:
dependencies:
domelementtype: 2.3.0

@ -1,17 +1,41 @@
import request from '@/utils/request'
import request from "@/utils/request";
export const login = (data: any) => {
return request({
url: '/sys/login',
method: 'post',
data
})
}
return request({
url: "/sys/login",
method: "post",
data,
});
};
export const getCode = (time: any) => {
return request({
url: '/sys/randomImage/' + time,
})
}
return request({
url: "/sys/randomImage/" + time,
});
};
// 获取用户信息
export const getUserInfo = () => {
return request({
url: "/sys/user/getUserInfo",
method: "get",
});
};
// 实验步骤
export const setStep = (params: any) => {
return request({
url: "/experimentrecords/xnExperimentRecords/check",
method: "get",
params
})
}
// 获取步骤id
export const getStepId = () => {
return request({
url: "/experimentrecords/xnExperimentRecords/getProcedureList",
method: "get",
})
}
//试题表
export const subTestapi = () => {
return request({

@ -0,0 +1,25 @@
import request from '@/utils/request'
export const getCode = (time: any) => {
return request({
url: '/sys/randomImage/' + time,
})
}
// 获取院系列表
export const getFaculties = (params: any) => {
return request({
url: '/sys/sysDepart/stu',
params,
})
}
// 注册
export const sturegister = (data: any) => {
return request({
url: '/sys/user/stuRegister',
method: 'POST',
data,
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

@ -6,68 +6,146 @@
<div class="main-content">
<el-row style="display: flex; justify-content: center">
<el-col>
<el-form
:rules="rules"
:model="formModel"
ref="formRef"
size="large"
autocomplete="off"
v-if="isRegister"
>
<el-form-item prop="username">
<el-input
v-model="formModel.username"
:prefix-icon="User"
placeholder="请输入账号"
></el-input>
</el-form-item>
<el-form-item prop="studentNumb">
<el-input
v-model="formModel.studentNumb"
:prefix-icon="Avatar"
placeholder="请输入学号"
></el-input>
</el-form-item>
<el-form-item prop="name">
<el-input
v-model="formModel.name"
:prefix-icon="Stamp"
placeholder="请输入姓名"
></el-input>
<el-form :rules="rules" :model="formModel" ref="formRef" size="large" autocomplete="off" v-if="isRegister">
<el-form-item prop="username" class="custom-form-item">
<div style="display: flex; align-items: center; color: pink">
<div class="left" style="display: flex; align-items: center;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<User />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">用户账号</div>
</div>
<div class="right">
<el-input v-model="formModel.username" style="border-color: #20bec8;"
placeholder="请输入用户账号"></el-input>
</div>
</div>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="formModel.password"
:prefix-icon="Lock"
type="password"
placeholder="请输入密码"
></el-input>
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Lock />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">用户密码</div>
</div>
<div class="right">
<el-input type="password" v-model="formModel.password" style="border-color: #20bec8"
placeholder="请输入密码" show-password></el-input>
</div>
</div>
</el-form-item>
<el-form-item prop="repassword">
<el-input
v-model="formModel.repassword"
:prefix-icon="Lock"
type="password"
placeholder="请输入再次密码"
></el-input>
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Lock />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">确认密码</div>
</div>
<div class="right">
<el-input type="password" v-model="formModel.repassword" style="border-color: #20bec8"
placeholder="请再次输入密码" show-password></el-input>
</div>
</div>
</el-form-item>
<el-form-item prop="name" class="custom-form-item">
<div style="display: flex; align-items: center; color: pink">
<div class="left" style="display: flex; align-items: center;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Stamp />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">姓名</div>
</div>
<div class="right">
<el-input v-model="formModel.name" style="border-color: #20bec8;" placeholder="请输入姓名"></el-input>
</div>
</div>
</el-form-item>
<el-form-item prop="clssid">
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Avatar />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">班级</div>
</div>
<div class="right">
<el-cascader placeholder="请选择所属班级" :props="props" style="width: 142%; height: 0.2344rem"
v-model="formModel.clssid" @change="handleChange" />
</div>
</div>
</el-form-item>
<!-- <el-cascader :props="props" style="width: 100%; height: 0.2344rem" v-model="formModel.clssid" /> -->
<el-form-item prop="studentNumb">
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Avatar />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">学号</div>
</div>
<div class="right">
<el-input v-model="formModel.studentNumb" style="border-color: #20bec8"
placeholder="请输入学号"></el-input>
</div>
</div>
</el-form-item>
<el-form-item prop="mobile">
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Iphone />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">手机号</div>
</div>
<div class="right">
<el-input v-model="formModel.mobile" style="border-color: #20bec8" placeholder="请输入手机号"></el-input>
</div>
</div>
</el-form-item>
<el-form-item>
<el-button
style="color: #3ad7e2; background-color: #0e2e5e; width: 150px"
class="button"
type="primary"
auto-insert-space
@click="register"
>
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Grid />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">验证码</div>
</div>
<div class="right">
<div class="captcha">
<el-input v-model="formModel.captcha" style="height: 0.2344rem" maxlength="4" />
<div class="code" @click="getcodeinfo">
<img :src="codeUrl" alt="" srcset="" />
</div>
</div>
</div>
</div>
</el-form-item>
<el-form-item style="margin-bottom: -30px;">
<el-button style="color: #3ad7e2; background-color: #0e2e5e; width: 165px" class="button" type="primary"
auto-insert-space @click="register">
注册
</el-button>
<el-button
style="color: #3ad7e2; background-color: #0e2e5e; width: 150px"
class="button"
type="primary"
auto-insert-space
@click="isRegister = false"
>
<el-button style="color: #3ad7e2; background-color: #0e2e5e; width: 165px" class="button" type="primary"
auto-insert-space @click="toLogin">
返回到登录页
</el-button>
</el-form-item>
@ -78,77 +156,87 @@
</el-link>
</el-form-item> -->
</el-form>
<el-form
:model="formModel"
:rules="rules"
ref="formRef"
size="large"
autocomplete="off"
v-else
class="custom-form"
>
<el-form-item prop="username">
<el-form :model="formModel" :rules="rules" ref="formRef" size="large" autocomplete="off" v-else
class="custom-form">
<el-form-item prop="username" class="custom-form-item">
<div style="display: flex; align-items: center; color: pink">
<div class="left" style="display: flex; align-items: center">
<div class="left" style="display: flex; align-items: center;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<user />
<User />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">用户名</div>
</div>
<div class="right">
<el-input
v-model="formModel.username"
style="border-color: #20bec8; background-color: pink"
placeholder="请输入用户名"
></el-input>
<el-input v-model="formModel.username" style="border-color: #20bec8;" placeholder="请输入用户名"></el-input>
</div>
</div>
</el-form-item>
<el-form-item label="学号" prop="studentNumb">
<el-input
v-model="formModel.studentNumb"
:prefix-icon="Avatar"
placeholder="请输入学号"
></el-input>
<el-form-item prop="studentNumb">
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Avatar />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">学号</div>
</div>
<div class="right">
<el-input v-model="formModel.studentNumb" style="border-color: #20bec8"
placeholder="请输入学号"></el-input>
</div>
</div>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input
name="password"
:prefix-icon="Lock"
type="password"
placeholder="请输入密码"
v-model="formModel.password"
></el-input>
<el-form-item prop="password">
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Lock />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">密码</div>
</div>
<div class="right">
<el-input type="password" v-model="formModel.password" style="border-color: #20bec8"
placeholder="请输入密码"></el-input>
</div>
</div>
</el-form-item>
<el-form-item label="验证码">
<div class="captcha">
<el-input
v-model="formModel.captcha"
style="height: 0.2344rem"
maxlength="4"
/>
<div class="code" @click="getcodeinfo">
<img :src="codeUrl" alt="" srcset="" />
<el-form-item>
<div style="display: flex; align-items: center;">
<div class="left" style="display: flex; align-items: center ;width: 90px;">
<div style="padding-right: 10px; color: #1084c1">
<el-icon class="bold-icon">
<Grid />
</el-icon>
</div>
<div style="padding-right: 10px; color: #2592a1">验证码</div>
</div>
<div class="right">
<div class="captcha">
<el-input v-model="formModel.captcha" style="height: 0.2344rem" maxlength="4" />
<div class="code" @click="getcodeinfo">
<img :src="codeUrl" alt="" srcset="" />
</div>
</div>
</div>
</div>
</el-form-item>
<!-- <el-form-item label="验证码">
<div class="captcha">
<el-input v-model="formModel.captcha" style="height: 0.2344rem" maxlength="4" />
<div class="code" @click="getcodeinfo">
<img :src="codeUrl" alt="" srcset="" />
</div>
</div>
</el-form-item> -->
<el-form-item>
<el-button
class="hexagon-button"
type="primary"
auto-insert-space
@click="login"
>登录</el-button
>
<el-button
class="hexagon-button"
type="primary"
auto-insert-space
@click="isRegister = true"
>去注册</el-button
>
<el-button class="hexagon-button" type="primary" auto-insert-space @click="login">登录</el-button>
<el-button class="hexagon-button" type="primary" auto-insert-space @click="toRegister">去注册</el-button>
</el-form-item>
</el-form>
</el-col>
@ -161,11 +249,12 @@
<script setup lang="ts">
// import { ref } from "vue"
// import { onMounted, reactive, ref, toRefs, watch } from "vue";
import { ElMessage, ElMessageBox } from 'element-plus'
import settingStore from "@/store/modules/setting";
import { User, Lock, Avatar, Stamp } from "@element-plus/icons-vue";
import { User, Lock, Avatar, Stamp, Grid, Iphone } from "@element-plus/icons-vue";
import { ref } from "vue";
import userStore from "@/store/modules/user";
import { getCode } from "@/api";
import { getCode, sturegister, getFaculties } from '@/api/user'
import { useRouter } from "vue-router";
const router = useRouter()
const setting = settingStore();
@ -176,12 +265,48 @@ const isRegister = ref(false);
const formRef = ref();
const formModel = ref({
username: "",
studentNumb: "",
name: "",
password: "",
repassword: "",
name: "",
clssid: '',
studentNumb: "",
mobile: '',
captcha: "",
});
const FacultiesList = ref([])
const getFacultiesList = async (data: any) => {
const res: any = await getFaculties(data)
console.log(res, 'res11')
FacultiesList.value = res.result
}
const deepValues = ref([])
//
const props = {
lazy: true,
checkStrictly: true,
emitPath: false,
async lazyLoad(node: any, resolve: any) {
console.log(node);
deepValues.value = node.pathValues
await getFacultiesList({
primaryType: node.level + 1,
pid: node.value,
})
const nodes = FacultiesList.value.map((item: any) => ({
value: item.id,
label: item.name,
}))
resolve(nodes)
},
}
const handleChange = (e: any) => {
console.log(e);
formModel.value.clssid = e
}
//
const rules = {
username: [
@ -198,7 +323,7 @@ const rules = {
{
min: 5,
max: 11,
message: "学号长度最小五位最大十位",
message: "学号长度最小五位最大十位",
trigger: ["change", "blur"],
},
],
@ -231,10 +356,64 @@ const rules = {
trigger: "blur",
},
],
clssid: [
{ required: true, message: "请选择所属班级", trigger: "blur" },
],
mobile: [
{ required: true, message: "请输入手机号", trigger: "blur" },
{
pattern: /^1[3-9]\d{9}$/,
message: "手机号格式不正确",
trigger: ["change", "blur"],
},
]
};
const register = async () => {
await formRef.value.validate();
console.log("开始注册i请求");
console.log("开始注册请求");
let data = {
clssid: formModel.value.clssid,
mobile: formModel.value.mobile,
captcha: formModel.value.captcha,
checkKey: 1629428467008,
password: formModel.value.password,
username: formModel.value.username,
realname: formModel.value.name,
workno: formModel.value.studentNumb,
depid: deepValues.value.slice(0, 2).join(',')
};
try {
const res: any = await sturegister(data)
formModel.value = {
username: "",
password: "",
repassword: "",
name: "",
clssid: '',
studentNumb: "",
mobile: '',
captcha: "",
}
ElMessage.success(`注册成功`)
isRegister.value = false
} catch (error) {
console.log(error);
getcodeinfo()
}
// getcodeinfo()
// console.log(11111);
// ElMessage.warning(res.message)
// console.log(res)
};
const codeUrl = ref("");
const getcodeinfo = async () => {
@ -258,11 +437,19 @@ const login = async () => {
username: formModel.value.username,
};
const res = await user.logIn(data);
if(res){
if (res) {
router.push('/')
}
};
const toRegister = () => {
isRegister.value = true
getcodeinfo();
}
const toLogin = () => {
isRegister.value = false
getcodeinfo();
}
</script>
<style lang="less" scoped>
@ -299,27 +486,32 @@ const login = async () => {
margin: 0;
background: url("../assets/images/login.png") no-repeat;
background-position: center;
background-size: 50% auto;
}
.captcha {
width: 100%;
height: 100%;
position: relative;
.code {
width: 100%;
height: 100%;
position: absolute;
top: 0;
right: 0;
width: 105px;
height: 100%;
// background-color: pink;
display: flex;
align-items: center;
img {
width: 100%;
height: 100%;
position: relative;
.code {
width: 100%;
height: 100%;
position: absolute;
top: 0;
right: 0;
width: 105px;
height: 100%;
// background-color: pink;
display: flex;
align-items: center;
img {
width: 100%;
height: 100%;
}
}}
}
}
}
}
.hexagon-button {
@ -337,17 +529,17 @@ const login = async () => {
font-size: 18px;
}
// .custom-form .el-form-item__label {
// color: #409eff;
// /* */
// font-size: 14px;
// font-weight: bold;
// .el-form-item__label {
// color: #0e2e5e;
// }
// .bold-icon svg {
// stroke-width: 9;
// /* */
// .el-form-item__error {
// left: 80px;
// }
.el-form-item__label {
color: #0e2e5e;
.el-input {
width: 300px;
}
:deep(.el-form-item__error) {
left: 110px;
}
</style>

@ -7,7 +7,14 @@ import 'element-plus/dist/index.css'; // 引入 Element Plus 的样式文件
import '@/utils/rem.js'
import DataVVue3 from '@kjgl77/datav-vue3'
import pinia from '@/store/index'
//引入依赖和语言
import 'highlight.js/styles/stackoverflow-light.css'
// import hljs from "highlight.js/lib/core";
// import hljsVuePlugin from "@highlightjs/vue-plugin";
// import java from "highlight.js/lib/languages/java";
const app = createApp(App)
// hljs.registerLanguage("java", java);
// app.use(hljsVuePlugin);
app.use(ElementPlus)
app.use(pinia)
app.use(DataVVue3)

@ -14,10 +14,19 @@ router.beforeEach((to: any, from: any, next: any) => {
} else {
const token = getToken();
if (token) {
next();
console.log(store.userInfo);
if (store.userInfo) {
next();
} else {
store.getUserInfo().then(() => {
next();
});
}
// next();
} else {
next("/login");
}
}
});
export default router;
export default router;

@ -19,7 +19,12 @@ const routerList: any = [
path: "program",
name: "Program",
component: () => import("@/views/program/index.vue"),
}
},
{
path: "compiler",
name: "Compiler",
component: () => import("@/views/compiler/index.vue"),
},
],
},
{

@ -16,6 +16,11 @@ const settingStore = defineStore("settingStore", {
sdsz: 0, // 湿度数值
falg: false,
timer: null,
experimentPreservation: false, // 是否设计好实验
saveRoute: false, // 是否保存路由
stepIds: null,
wenduCode: null,
shiduCode:null
};
},
actions: {
@ -27,7 +32,7 @@ const settingStore = defineStore("settingStore", {
this.qw = value;
},
setValue(value: number, name: string) {
setValue(value: number | boolean, name: string) {
this[name] = value;
},
openHeating() {
@ -46,7 +51,7 @@ const settingStore = defineStore("settingStore", {
}
},
calculateTemperature() {
this.qw <= 0 ? this.qw=1 : this.qw;
this.qw <= 0 ? (this.qw = 1) : this.qw;
const a = (100000 * this.zl * this.srmj) / this.jrgl;
let time = 0;
let currentTemp = this.qw;
@ -61,6 +66,40 @@ const settingStore = defineStore("settingStore", {
clearInterval(interval);
}
time += 1; // 每秒增加 1s
}, 1000);
},
simulateHeatingAndHumidifying() {
// 计算时间常数
const a = (100000 * this.zl * this.srmj) / this.jrgl;
const b = (10000 * this.jsmj) / this.jsgl;
let time = 0;
let currentTemp = this.qw;
let currentHumidity = this.cssd;
const interval = setInterval(() => {
// 计算温度
currentTemp = (1 - Math.exp(-time / a)) * 100 + this.qw;
if (currentTemp > 100) currentTemp = 100;
// 计算湿度
currentHumidity = (1 - Math.exp(-time / b)) * 100 + this.cssd;
if (currentHumidity > 100) currentHumidity = 100;
console.log(
`时间: ${time}s, 温度: ${currentTemp.toFixed(
2
)}°C, 湿度: ${currentHumidity}%RH`
);
this.qw = currentTemp >= 100 ? 100 : currentTemp;
this.cssd = currentHumidity >= 100 ? 100 : Number(currentHumidity.toFixed(2));
// 停止加热 & 加湿
if (currentTemp >= 100 && currentHumidity >= 100) {
console.log("温度和湿度均达到上限,停止模拟!");
clearInterval(interval);
}
time += 1; // 每秒增加 1s
}, 1000);
},

@ -1,30 +1,37 @@
import { defineStore } from "pinia";
import { getToken,setToken } from "@/utils/auth";
import { login } from "@/api";
import { getToken, setToken } from "@/utils/auth";
import { login, getUserInfo } from "@/api";
import { ElMessage } from "element-plus";
const userStore = defineStore("userStore", {
state: () => ({
token: getToken(),
userInfo: {},
userInfo: null,
}),
actions: {
async logIn(form: any) {
console.log(form);
const res: any = await login(form);
// if(res.code === 500) return ElMessage.error(res.msg)
if(res.code !== 200) {
ElMessage.error(res.msg)
return false
if (res.code !== 200) {
ElMessage.error(res.msg);
return false;
}
this.token = res.result.token;
this.userInfo = res.result.userInfo;
setToken(this.token);
console.log(res);
return true
return true;
},
clearStatus() {
this.token = "";
this.userInfo = {};
this.userInfo = null;
},
async getUserInfo() {
const res:any = await getUserInfo();
this.userInfo = res.result.userInfo;
console.log(res);
// this.userInfo = res.result;
},
},
});

@ -0,0 +1,12 @@
// 格式化时间 年月日时分秒
export function formatDate(date: any) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
console.log(`${year}-${month}-${day} ${hours}:${minutes}:${seconds}`);
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

@ -0,0 +1,16 @@
import { setStep, getStepId } from "../api/index";
import settingStore from "../store/modules/setting";
import pinia from "@/store";
const useStore = settingStore(pinia);
export const setStepEvent = async (step: number, controlsSt: string) => {
let id: any = null;
if (!useStore.stepIds) {
const data: any = await getStepId();
useStore.stepIds = data.result.map((item: any) => item.id);
id = useStore.stepIds[step - 1];
// return id;
await setStep({ id, controlsSt });
} else {
await setStep({ id: useStore.stepIds[step - 1], controlsSt });
}
};

@ -0,0 +1,77 @@
<template>
<div class="container">
<div class="main">
<!-- <pre><code ref="editor" class="edit-text html" contenteditable="true" @input="highlightCode">console.log('Hello, World!');</code></pre> -->
<div class="edit-text" contenteditable="true" spellcheck="false">
<!-- <highlightjs ref="editor" :language="language" :code="code" v-model="code" contenteditable="true" @input="highlightCode"></highlightjs> -->
oisafkahsdkjfhasdf sdfhkjsahfdlkjas \n /n sldhfkajshfd salkdhflkasf asfasdf
</div>
</div>
<div class="setting">
<el-button>保存</el-button>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import hljs from "highlight.js/lib/core";
const editor = ref(null);
const code = ref('console.log("Hello, World!");');
const highlightCode = () => {
const codeBlock = editor.value;
console.log(codeBlock);
if (codeBlock) {
hljs.highlightElement(code);
}
};
onMounted(() => {
// highlightCode();
});
</script>
<style scoped>
.container {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
margin-top: 100px;
/* position: relative; */
}
.main {
width: 1442px;
height: 753px;
background-color: pink;
background: url("../../assets/images/idea.png") no-repeat;
background-size: contain;
background-position: center center;
position: relative;
}
.edit-text {
position: absolute;
left: 410px;
top: 60px;
width: 700px;
height: 670px;
background-color: #1e1e1e;
color: #fff;
font-family: "Courier New", monospace;
padding: 10px;
border-radius: 5px;
overflow: auto;
outline: none;
line-height: 30px;
}
.setting{
position: absolute;
top: 20px;
right: 100px;
}
</style>

@ -6,12 +6,31 @@
<div class="W">W</div>
<div class="t">t</div>
<div class="T">T</div>
<textarea type="textarea" style="width: 100%;height: 100%;border: none;font-size: 14px;line-height: 30px;" />
<textarea
type="textarea"
@change="wenduCodeChange"
style="
width: 100%;
height: 100%;
border: none;
font-size: 14px;
line-height: 30px;
"
/>
</div>
</template>
<script setup>
import { ref, computed, nextTick, watch, onMounted } from "vue";
import { ref } from "vue";
import settingStore from "@/store/modules/setting";
const useSettingStore = settingStore();
const value = ref("");
let code = "float a;a=1000000*M*S/W;T+(1-exp(-t/a))*100+T0;if(T>=100){T=100;}";
const wenduCodeChange = (e) => {
//
useSettingStore.wenduCode = e.target.value.replace(/\n/g, "");
// console.log(e.target.value.replace(/\n/g, '') === code);
};
</script>
<style scoped>
@ -27,7 +46,6 @@ import { ref, computed, nextTick, watch, onMounted } from "vue";
left: -25px;
border: 1px solid #ccc;
color: #fff;
}
.M {
position: absolute;
@ -35,7 +53,6 @@ import { ref, computed, nextTick, watch, onMounted } from "vue";
left: -25px;
border: 1px solid #ccc;
color: #fff;
}
.S {
position: absolute;
@ -43,30 +60,26 @@ import { ref, computed, nextTick, watch, onMounted } from "vue";
left: -17px;
border: 1px solid #ccc;
color: #fff;
}
.W{
.W {
position: absolute;
top: 180px;
left: -17px;
border: 1px solid #ccc;
color: #fff;
}
.t{
.t {
position: absolute;
top: 240px;
left: -17px;
border: 1px solid #ccc;
color: #fff;
}
.T{
.T {
position: absolute;
top: 50%;
right: -17px;
border: 1px solid #ccc;
color: #fff;
}
</style>

@ -6,12 +6,18 @@
<!-- <div class="W">W</div> -->
<div class="t">t1</div>
<div class="T">R</div>
<textarea type="textarea" style="width: 100%;height: 100%;border: none;font-size: 14px;line-height: 30px;" />
<textarea type="textarea" @change="wenduCodeChange" style="width: 100%;height: 100%;border: none;font-size: 14px;line-height: 30px;" />
</div>
</template>
<script setup>
import { ref, computed, nextTick, watch, onMounted } from "vue";
import { ref } from "vue";
import settingStore from "@/store/modules/setting";
const useSettingStore = settingStore();
const value = ref("");
const wenduCodeChange = (e) => {
useSettingStore.shiduCode = e.target.value.replace(/\n/g, "");
}
</script>
<style scoped>

@ -69,8 +69,13 @@ import shiduValueSetting from "./components/shiduValueSetting.vue";
import setzijie from "./components/setzijie.vue";
import { ElMessage } from "element-plus";
import tipView from "@/assets/images/guanxitu.png";
import { useRouter } from "vue-router";
import useSettingStore from "@/store/modules/setting";
import { setStepEvent } from "@/utils/setStep";
import { formatDate } from "@/utils";
let graph = null;
const router = useRouter();
const settingStore = useSettingStore();
//
const portConfig = {
top: {
@ -165,12 +170,12 @@ onMounted(() => {
});
},
validateConnection({ sourceCell, targetCell }) {
//
if (sourceCell && targetCell && sourceCell.id === targetCell.id) {
return false;
}
return true;
//
if (sourceCell && targetCell && sourceCell.id === targetCell.id) {
return false;
}
return true;
},
},
highlighting: {
magnetAdsorbed: {
@ -326,7 +331,7 @@ onMounted(() => {
// 1
graph.addNode({
shape: "custom-vue-node-wenBenYu",
id:'32',
id: "32",
width: 210,
height: 300,
x: 320,
@ -366,7 +371,7 @@ onMounted(() => {
// 2
graph.addNode({
shape: "custom-vue-node-wenBenYu2",
id:'33',
id: "33",
width: 210,
height: 300,
x: 400,
@ -795,11 +800,11 @@ onMounted(() => {
});
graph.on("edge:connected", ({ edge }) => {
const data = {
type: "add",
edge: edge.toJSON(), // toJSON port
type: "add",
edge: edge.toJSON(), // toJSON port
};
saveToLocalStorage(data);
})
});
// 线
graph.on("edge:removed", ({ edge }) => {
@ -810,11 +815,11 @@ onMounted(() => {
saveToLocalStorage(data);
});
setTimeout(() => {
restoreGraph()
restoreGraph();
}, 1000);
graph.on('edge:added', ({ edge }) => {
console.log('新增连线数据:', edge.toJSON());
})
graph.on("edge:added", ({ edge }) => {
console.log("新增连线数据:", edge.toJSON());
});
// const nodes = graph.getNodes();
// console.log(nodes);
// const data = graph.toJSON();
@ -830,16 +835,44 @@ const onUndo = () => {
const onRedo = () => {
graph.redo();
};
const wenduCode = "float a;a=1000000*M*S/W;T+(1-exp(-t/a))*100+T0;if(T>=100){T=100;}";
const shiduCode = "float b;a=10000*S0/W1;R+(1-exp(-t1/b))*100+R0;if(R>=100){R=100;}";
const onSave = () => {
if (standardData.length !== formatEdges().length)
setStepEvent(3, formatDate(new Date()));
// console.log(removeDuplicateEdges(formatEdges()), standardData);
// return
if (standardData.length !== removeDuplicateEdges(formatEdges()).length)
return ElMessage.error("请完善数据");
validateRelationships(standardData, formatEdges());
if(settingStore.wenduCode != wenduCode){
return ElMessage.error("温度代码编写错误");
}
if(settingStore.shiduCode != shiduCode){
return ElMessage.error("湿度代码编写错误");
}
ElMessage.success("保存成功");
settingStore.setValue( true,'saveRoute');
router.push('/program')
// const data = graph.toJSON();
// console.log(data);
// const edges = graph.getEdges();
// console.log(formatEdges());
};
function removeDuplicateEdges(edges) {
const seen = new Set();
return edges.filter(edge => {
// source target
const key = edge.source < edge.target
? `${edge.source}-${edge.target}`
: `${edge.target}-${edge.source}`;
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
const formatEdges = () => {
const edges = graph.getEdges();
// console.log(edges);
@ -1081,38 +1114,38 @@ const onTip = () => {
function restoreGraph() {
const operations = loadFromLocalStorage();
//
operations
.filter(op => op.type === 'add' && op.node)
.forEach(op => graph.addNode(op.node));
//
operations
.filter((op) => op.type === "add" && op.node)
.forEach((op) => graph.addNode(op.node));
// 线
operations
.filter(op => op.type === 'add' && op.edge)
.forEach(op => {
const edgeData = op.edge;
// 线
operations
.filter((op) => op.type === "add" && op.edge)
.forEach((op) => {
const edgeData = op.edge;
// port port ID
if (!edgeData.source.port) edgeData.source.port = "70";
if (!edgeData.target.port) edgeData.target.port = "70";
// port port ID
if (!edgeData.source.port) edgeData.source.port = "70";
if (!edgeData.target.port) edgeData.target.port = "70";
graph.addEdge(edgeData);
});
graph.addEdge(edgeData);
});
}
const SESSION_KEY = 'graph_operations1';
const SESSION_KEY = "graph_operations1";
function saveToLocalStorage(data) {
const operations = JSON.parse(localStorage.getItem(SESSION_KEY)) || [];
operations.push(data);
localStorage.setItem(SESSION_KEY, JSON.stringify(operations));
const operations = JSON.parse(localStorage.getItem(SESSION_KEY)) || [];
operations.push(data);
localStorage.setItem(SESSION_KEY, JSON.stringify(operations));
}
function loadFromLocalStorage() {
return JSON.parse(localStorage.getItem(SESSION_KEY)) || [];
return JSON.parse(localStorage.getItem(SESSION_KEY)) || [];
}
function clearLocalStorage() {
localStorage.removeItem(SESSION_KEY);
localStorage.removeItem(SESSION_KEY);
}
</script>

@ -9,7 +9,7 @@ import { onMounted, watch } from "vue";
import * as echarts from "echarts";
import settingStore from "@/store/modules/setting";
const useSettingStore = settingStore();
var value = useSettingStore.cssd * 100;
var value = useSettingStore.cssd;
var myChart = null;
const initChart = () => {
const option = {
@ -187,7 +187,7 @@ const initChart = () => {
fontSize: 20,
distance: -70,
formatter: function (params) {
var value = params.toFixed(0);
var value = params;
if (value == 0.0) {
return "0";
@ -235,7 +235,7 @@ const initChart = () => {
},
detail: {
formatter: function (params) {
return params / 100;
return params ;
},
fontSize: 30,
color: "#fff",
@ -261,7 +261,7 @@ onMounted(() => {
watch(
() => useSettingStore.cssd,
(newValue) => {
value=newValue * 100
value=newValue
setTimeout(() => {
initChart();
}, 100);

@ -43,7 +43,9 @@
<el-button @click="onUndo">撤回</el-button>
<el-button @click="onRedo">恢复</el-button>
<el-button @click="clearLocalStorage">清除缓存</el-button>
<el-button @click="onSave">运行</el-button>
<el-button @click="onSave">{{
useSettingStore.experimentPreservation ? "运行" : "保存"
}}</el-button>
<el-button @click="onTip">提示</el-button>
</div>
<div class="tip-view">
@ -80,8 +82,11 @@ import settingStore from "@/store/modules/setting";
import Yibiao from "./components/yibiao.vue";
import { ElMessage } from "element-plus";
import tipView from "@/assets/images/chengxv.png";
import { useRouter } from "vue-router";
import { setStepEvent } from "@/utils/setStep";
import { formatDate } from "@/utils";
const useSettingStore = settingStore();
const router = useRouter();
// console.log(useSettingStore.qw);
//
@ -189,14 +194,20 @@ onMounted(() => {
//
graph.on("node:click", ({ cell }: any) => {
// console.log(cell.store.previous.name);
// console.log(cell);
console.log(cell);
if (!useSettingStore.saveRoute) {
ElMessage({
message: "请先完成配置",
type: "warning",
});
return;
}
if (
cell.shape === "deom" ||
cell.shape === "yibiao" ||
cell.shape === "rect" ||
cell.store.previous.name === "wdsz" ||
cell.store.previous.name === "sdsz"
cell.shape === "custom-text-wdsz" ||
cell.shape === "custom-text-sdsz"
)
return;
// if (cell.store.previous.name === "qw") {
@ -220,7 +231,7 @@ onMounted(() => {
// ]);
});
graph.on("node:added", ({ node }:any) => {
graph.on("node:added", ({ node }: any) => {
const data = {
type: "add",
node: node.toJSON(),
@ -229,7 +240,7 @@ onMounted(() => {
saveToLocalStorage(data);
});
graph.on("node:removed", ({ node }:any) => {
graph.on("node:removed", ({ node }: any) => {
const data = {
type: "remove",
id: node.id,
@ -1057,7 +1068,40 @@ const saveNodeData = () => {
if (falg.value) {
const value = Number(selectedNodeData.value.label);
// useSettingStore.setqw(value);
useSettingStore.setValue(value, selectedNodeData.value.name);
console.log(value, selectedNodeData.value.name);
switch (node.shape) {
case "custom-text":
useSettingStore.setValue(parseInt(node.label), "qw"); //
break;
case "custom-text-zl":
useSettingStore.setValue(parseInt(node.label), "zl"); //
break;
case "custom-text-srmj":
useSettingStore.setValue(parseInt(node.label), "srmj"); //
break;
case "custom-text-jrgl":
useSettingStore.setValue(parseInt(node.label), "jrgl"); //
break;
case "custom-text-jrmj":
useSettingStore.setValue(parseInt(node.label), "jrmj"); //
break;
case "custom-text-prot":
useSettingStore.setValue(node.label, "port"); //
break;
case "custom-text-IP":
useSettingStore.setValue(node.label, "ip"); // IP
break;
case "custom-text-cssd":
useSettingStore.setValue(parseInt(node.label), "cssd"); // 湿
break;
case "custom-text-jsgl":
useSettingStore.setValue(parseInt(node.label), "jsgl"); // 湿
break;
case "custom-text-jsmj":
useSettingStore.setValue(parseInt(node.label), "jsmj"); // 湿
break;
}
// useSettingStore.setValue(value, selectedNodeData.value.name);
graph.getNodes().forEach((node: any) => {
// console.log(node.label);
@ -1140,42 +1184,6 @@ const onRedo = () => {
};
const sdsz = ref<any>(null);
const onSave = () => {
// console.log(graph.toJSON());
graph.toJSON().cells.forEach((item: any) => {
console.log(item);
switch (item.shape) {
case "custom-text":
useSettingStore.setValue(parseInt(item.attrs.text.text),item.name, );
break;
case "custom-text-zl":
useSettingStore.setValue(parseInt(item.attrs.text.text),item.name, );
break;
case "custom-text-srmj":
useSettingStore.setValue(parseInt(item.attrs.text.text),item.name, );
break;
case "custom-text-jrgl":
useSettingStore.setValue(parseInt(item.attrs.text.text),item.name, );
break;
case "custom-text-prot":
useSettingStore.setValue(parseInt(item.attrs.text.text),item.name, );
break;
case "custom-text-cssd":
useSettingStore.setValue(parseInt(item.attrs.text.text),item.name, );
break;
}
});
// return;
clearLocalStorage();
const data = graph.toJSON().cells.map((item: any) => {
return {
node: item,
type: "add",
};
});
console.log(data);
localStorage.setItem(SESSION_KEY, JSON.stringify(data));
if (
!hasExactNames(graph.getNodes(), [
"custom-text",
@ -1196,6 +1204,156 @@ const onSave = () => {
message: "请填写完整信息",
});
}
if (!useSettingStore.experimentPreservation) {
useSettingStore.setValue(true, "experimentPreservation");
router.push("/designRoute");
return;
}
graph.toJSON().cells.forEach((item: any) => {
switch (item.shape) {
case "custom-text":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写初始温度信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
case "custom-text-zl":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写质量信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
case "custom-text-srmj":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写散热面积信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
case "custom-text-jrgl":
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写加热功率信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
// case "custom-text-prot":
// useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
// break;
case "custom-text-cssd":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写初始湿度信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
case "custom-text-jsgl":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写加湿功率信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
case "custom-text-jsmj":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写加湿面积信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
case "custom-text-IP":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写ip设置信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
case "custom-text-prot":
// console.log(parseInt(item.attrs.text.text));
if (!parseInt(item.attrs.text.text)) {
ElMessage({
type: "warning",
message: "请请填写设定温度信息",
});
return;
}
useSettingStore.setValue(parseInt(item.attrs.text.text), item.name);
break;
}
});
if (useSettingStore.experimentPreservation) {
const arr = [
useSettingStore.qw,
useSettingStore.zl,
useSettingStore.srmj,
useSettingStore.jrgl,
useSettingStore.port,
useSettingStore.cssd,
useSettingStore.jsmj,
useSettingStore.jsgl,
useSettingStore.ip,
];
console.log(
arr,
arr.every((item) => item !== 0 && item !== "")
);
//
if (!arr.every((item) => item !== 0 && item !== "")) {
return ElMessage({
type: "warning",
message: "请完善配置信息",
});
}
// console.log(graph.toJSON());
// return;
clearLocalStorage();
const data = graph.toJSON().cells.map((item: any) => {
return {
node: item,
type: "add",
};
});
console.log(data);
localStorage.setItem(SESSION_KEY, JSON.stringify(data));
}
csedNode.value = graph
.getNodes()
.find((node: any) => node.shape === "custom-text-wdsz");
@ -1205,7 +1363,10 @@ const onSave = () => {
console.log(csedNode.value);
sdsz.value.label = useSettingStore.cssd;
// useSettingStore.openHeating();
useSettingStore.calculateTemperature();
// useSettingStore.calculateTemperature();
useSettingStore.simulateHeatingAndHumidifying();
setStepEvent(4, formatDate(new Date()));
// const data = graph.toJSON();
// console.log(data);
// const edges = graph.getEdges();
@ -1213,15 +1374,19 @@ const onSave = () => {
};
function hasExactNames(arr: any, names: any) {
// name
const nameList = arr.map((obj:any) => obj.shape);
const nameList = arr.map((obj: any) => obj.shape);
console.log(
nameList,
names,
names.every((name:any) => nameList.filter((n:any) => n === name).length === 1)
names.every(
(name: any) => nameList.filter((n: any) => n === name).length === 1
)
);
// names nameList
return names.every((name:any) => nameList.filter((n:any) => n === name).length === 1);
return names.every(
(name: any) => nameList.filter((n: any) => n === name).length === 1
);
}
watch(
() => useSettingStore.qw,
@ -1234,10 +1399,22 @@ watch(
}
}
);
watch(
() => useSettingStore.cssd,
(newValue: number) => {
console.log(newValue, "newValue");
console.log(sdsz.value, "sdsz.value");
if (sdsz.value) {
sdsz.value.label = newValue;
}
}
);
const SESSION_KEY = "graph_operations";
function saveToLocalStorage(data:any) {
const operations = JSON.parse(localStorage.getItem(SESSION_KEY) as string) || [];
function saveToLocalStorage(data: any) {
const operations =
JSON.parse(localStorage.getItem(SESSION_KEY) as string) || [];
operations.push(data);
localStorage.setItem(SESSION_KEY, JSON.stringify(operations));
}
@ -1253,7 +1430,7 @@ function clearLocalStorage() {
function restoreGraph() {
const operations = loadFromLocalStorage();
operations.forEach((op:any) => {
operations.forEach((op: any) => {
if (op.type === "add") {
graph.addNode(op.node);
} else if (op.type === "remove") {

@ -7,7 +7,7 @@
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"moduleResolution": "node",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,

Loading…
Cancel
Save