This commit is contained in:
oneao committed 2026-03-19 22:15:36 +08:00
1 parent 4aaa93df7d
commit c330e52fd3
66 files changed
+7386 -4

No files matched your search

@@ -0,0 +1,421 @@
<script lang="js" setup>
import { loginApi } from "@/request/api";
import { useUserStore } from "@/store/user";
import { ElMessage } from "element-plus";
import { useRouter } from "vue-router";
import Vcode from "vue3-puzzle-vcode";
import { reset401Flag } from "@/request";
const router = useRouter();
const userStore = useUserStore();
const form = ref({
orgid: userStore.userInfo.orgid,
userid: userStore.userInfo.userid,
password: "",
});
const showVcode = ref(false);
const loginLoading = ref(false);
const linkList = ref([
{
title: "新手上路",
icon: "solar:key-bold",
href: "http://bbs.g3soft.cn/forum.php?mod=viewthread&tid=115&extra=page%3D1",
},
{
title: "会员活动",
icon: "mingcute:vip-1-fill",
href: "http://www.g3soft.cn/help/guide/promotion.html",
},
{
title: "视频教程",
icon: "material-symbols:auto-videocam-rounded",
href: "http://bbs.g3soft.cn/forum.php?mod=viewthread&tid=86&extra=page%3D1",
},
{
title: "常见问题",
icon: "ic:baseline-help",
href: "http://bbs.g3soft.cn/forum.php?mod=forumdisplay&fid=37",
},
]);
const endLinkList = ref([
{
title: "圆通官网",
href: "http://www.g3soft.cn",
},
{
title: "申请试用",
href: "http://dns.g3soft.cn/demo/jsys/login/login.jsp",
},
{
title: "联系我们",
href: "http://www.g3soft.cn/aboutus.html",
},
{
title: "客服热线: 0574-87812201",
href: "",
},
]);
function toHref(href) {
if (href) {
window.open(href, "_blank");
}
}
function onVcodeShow() {
if (form.value.orgid === "") {
ElMessage.error("机构码不能为空!");
return;
}
if (form.value.userid === "") {
ElMessage.error("用户名不能为空!");
return;
}
showVcode.value = true;
}
function onVcodeClose() {
showVcode.value = false;
}
function onVcodeSuccess() {
onVcodeClose();
loginLoading.value = true;
try {
loginApi(form.value.orgid, form.value.userid, form.value.password).then(
(res) => {
if (res.success) {
ElMessage.success("登录成功");
userStore.setUserInfo(
form.value.orgid,
form.value.userid,
res.data.username,
res.data.token,
);
router.push("/");
reset401Flag();
}
},
);
} finally {
loginLoading.value = false;
}
}
</script>
<template>
<div class="login-container">
<div class="login-header">
<div class="logo">
<img src="@/assets/logo.png" />
</div>
<div class="divider"></div>
<div class="name">网上服务平台</div>
</div>
<div class="login-body">
<div class="login-main">
<div class="tip">登录</div>
<div class="split"></div>
<div class="form">
<div class="form-item">
<div class="label required">机构码</div>
<el-input v-model="form.orgid">
<template #prefix>
<G3Icon icon="lucide:building" size="18" />
</template>
</el-input>
</div>
<div class="form-item">
<div class="label required">账号</div>
<el-input v-model="form.userid">
<template #prefix>
<G3Icon icon="lucide:user-round" size="18" />
</template>
</el-input>
</div>
<div class="form-item">
<div class="label">密码</div>
<el-input v-model="form.password" show-password>
<template #prefix>
<G3Icon icon="lucide:lock-keyhole" size="18" />
</template>
</el-input>
</div>
<el-button
size="large"
long
type="primary"
style="
background-color: #33dcd0;
border-color: #00d3c4;
font-size: 18px;
"
@click="onVcodeShow"
:loading="loginLoading"
>
登录
</el-button>
</div>
</div>
</div>
<div class="service-container">
<div class="service-title">
<div class="service-left"></div>
<div class="service-core">服务中心</div>
<div class="service-right"></div>
</div>
<div class="service-link">
<template v-for="(item, index) in linkList" :key="index">
<div class="link-item" @click="toHref(item.href)">
<div class="link-icon">
<G3Icon :icon="item.icon" size="38" color="#6cd6b3" />
</div>
<div class="link-title">{{ item.title }}</div>
</div>
</template>
</div>
</div>
<div class="end-container">
<template v-for="(item, index) in endLinkList" :key="index">
<div class="end-li" @click="toHref(item.href)">
{{ item.title }}
</div>
<div v-if="index !== endLinkList.length - 1" class="end-line"></div>
</template>
</div>
<Vcode :show="showVcode" @success="onVcodeSuccess" @close="onVcodeClose" />
</div>
</template>
<style lang="scss" scoped>
@use "@/styles/mixins.scss" as *;
.login-container {
display: flex;
flex-direction: column;
}
.login-header {
width: 50%;
display: flex;
align-items: center;
height: 81px;
margin-left: 25%;
.logo {
img {
height: 40px;
width: 120px;
}
}
.divider {
width: 1px;
height: 28px;
background-color: #ddd;
margin: 0px 24px;
}
.name {
color: #595959;
}
}
.login-body {
background-image: url("@/assets/login-bg.jpg");
width: 100%;
height: 420px;
position: relative;
.login-main {
position: absolute;
right: 25%;
top: 50%;
transform: translateY(-50%);
background-color: #fdfdfd;
padding: 24px 28px;
border-radius: 8px;
display: flex;
align-items: center;
flex-direction: column;
width: 320px;
}
.tip {
font-weight: bold;
font-size: 16px;
margin: 0 30px;
vertical-align: super;
}
.split {
height: 1px;
width: 100%;
border-bottom: 3px solid #00d3c4;
margin: 0 auto;
margin-top: 10px;
}
.form {
margin-top: 16px;
width: 100%;
display: flex;
flex-direction: column;
.form-item {
margin-bottom: 12px;
.label {
font-size: 14px;
margin-bottom: 8px;
}
.required {
&::before {
content: "*";
color: red;
margin-right: 4px;
}
}
:deep(.el-input__wrapper) {
height: 38px;
}
}
}
}
.service-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-bottom: 1px solid #e8e8e8;
padding-bottom: 56px;
flex-shrink: 0;
.service-title {
width: 100%;
max-width: 1200px;
margin: 40px 0px;
padding: 0 40px;
box-sizing: border-box;
.service-left {
position: relative;
display: inline-block;
width: 38%;
height: 2px;
background-color: #cccccc;
vertical-align: middle;
&::after {
content: "";
position: absolute;
right: -6px;
top: 50%;
transform: translateY(-50%);
width: 8px;
height: 8px;
background: #ccc;
border-radius: 50%;
}
}
.service-core {
display: inline-block;
width: 24%;
font-size: 24px;
text-align: center;
overflow: hidden;
height: 34px;
vertical-align: middle;
}
.service-right {
position: relative;
display: inline-block;
width: 38%;
height: 2px;
background-color: #cccccc;
vertical-align: middle;
&::before {
content: "";
position: absolute;
left: -6px;
top: 50%;
transform: translateY(-50%);
width: 8px;
height: 8px;
background: #ccc;
border-radius: 50%;
}
}
}
.service-link {
display: flex;
align-items: center;
justify-content: center;
@include flexGapWrap(40px, 160px);
.link-item {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
.link-icon {
padding: 12px;
border-radius: 999px;
border: 2px solid #6cd6b3;
display: flex;
align-items: center;
justify-content: center;
}
.link-title {
margin-top: 16px;
}
}
}
}
.end-container {
display: flex;
align-items: center;
justify-content: center;
color: #595959;
margin: 24px 0px;
.end-li {
font-size: 12px;
line-height: 12px;
display: inline-block;
cursor: pointer;
}
.end-line {
margin: 0 22px;
width: 1px;
height: 14px;
border-left: 1px solid #595959;
}
}
</style>
@@ -0,0 +1,11 @@
<script lang="js" setup>
</script>
<template>
<div class=""></div>
</template>
<style lang="css" scoped>
</style>
@@ -0,0 +1,9 @@
<script lang="js" setup></script>
<template>
<div class="">
<div></div>
</div>
</template>
<style lang="css" scoped></style>
@@ -0,0 +1,49 @@
<script setup lang="js">
const value = ref("");
const options = [
{
value: "Option1",
label: "Option1",
},
{
value: "Option2",
label: "Option2",
},
{
value: "Option3",
label: "Option3",
},
{
value: "Option4",
label: "Option4",
},
{
value: "Option5",
label: "Option5",
},
];
</script>
<template>
<G3Grid direction="row">
<G3GridGroup :label-width="80" :width="440" :column="2">
<G3GridItem label="1222222222222222222222222" content="2" :span="1" required>
<el-input type="textarea" v-model="value" />
</G3GridItem>
<G3GridItem label="3" :span="1">
<el-input />
</G3GridItem>
</G3GridGroup>
<G3GridGroup :label-width="80" :width="440" :column="2">
<G3GridItem label="1222222222222222222222222" content="2" :span="1" required>
<el-input type="textarea" v-model="value" />
</G3GridItem>
<G3GridItem label="3" :span="1">
<el-input />
</G3GridItem>
</G3GridGroup>
</G3Grid>
</template>
@@ -0,0 +1,714 @@
<script lang="js" setup>
import {
checkColumnsApi,
loadDataApi,
loadAllColumnsApi,
loadDataBySqlApi,
saveObjectApi,
} from "@/request/api";
import { ElMessage } from "element-plus";
import PreviewSql from "./preview-sql.vue";
import { diffObject } from "@/utils/diff";
const tableRef = ref();
const loading = ref(false);
const leftSize = ref(200);
const isCollapse = ref(false);
const showSql = ref(false);
const treeData = [{ b_id: "root", mc_b: "全部分类", isLeaf: false, children: [] }];
const treeProps = {
children: "children",
label: "mc_b",
};
const currentNode = ref(null);
const currentModule = ref(null);
const isSelectedNode = computed(() => !!currentNode.value);
const tableData = ref([]);
const currentRow = ref({});
const isSelectedRow = computed(() => !!currentRow.value?.col_FieldName);
let oldRowData = {};
const columns = [
{
prop: "col_field_name",
label: "字段",
width: 140,
fixed: "left",
},
{
prop: "col_caption",
label: "标题",
width: 100,
fixed: "left",
type: "input",
},
{
prop: "col_field_name_v",
label: "视图字段",
width: 100,
type: "input",
},
{
prop: "col_group_index",
label: "分组",
width: 80,
type: "input",
},
{
prop: "col_visible",
label: "显示",
width: 80,
type: "checkbox",
},
{
prop: "col_allow_readonly",
label: "只读",
width: 80,
type: "checkbox",
},
{
prop: "col_allow_null",
label: "可不输",
width: 80,
type: "checkbox",
},
{
prop: "col_allow_repeat",
label: "可重复",
width: 80,
type: "checkbox",
},
{
prop: "col_allow_reserve",
label: "可保留",
width: 80,
type: "checkbox",
},
{
prop: "col_search",
label: "可查找",
width: 80,
type: "checkbox",
},
{
prop: "col_search_order",
label: "查找顺序",
width: 100,
type: "input",
},
{
prop: "col_search_group_index",
label: "查找分组",
width: 100,
type: "input",
},
{
prop: "col_type",
label: "字段类型",
width: 100,
type: "option",
},
{
prop: "col_default_value",
label: "默认值",
width: 80,
type: "input",
},
{
prop: "col_width",
label: "宽度",
width: 80,
type: "input",
},
{
prop: "col_position",
label: "位置",
width: 80,
type: "input",
},
{
prop: "col_show_summary",
label: "合计",
width: 80,
type: "checkbox",
},
{
prop: "col_display_format",
label: "显示格式",
width: 100,
type: "input",
},
{
prop: "col_edit",
label: "编辑",
width: 80,
type: "checkbox",
},
{
prop: "col_edit_position",
label: "编辑位置",
width: 100,
type: "input",
},
{
prop: "col_edit_width",
label: "编辑宽度",
width: 100,
type: "input",
},
{
prop: "col_edit_height",
label: "编辑高度",
width: 100,
type: "input",
},
{
prop: "col_edit_source_data",
label: "编辑数据",
width: 160,
type: "input",
},
{
prop: "col_edit_source_field",
label: "下拉表显示字段",
width: 100,
type: "input",
},
{
prop: "col_edit_group_index",
label: "编辑分组",
width: 100,
type: "input",
},
{
prop: "col_edit_batch",
label: "批量编辑",
width: 100,
type: "checkbox",
},
{
prop: "col_show_property",
label: "属性",
width: 80,
type: "checkbox",
},
];
const editTypeOptions = [
{
value: "input",
label: "input",
},
{
value: "textarea",
label: "textarea",
},
{
value: "date",
label: "date",
},
{
value: "datetime",
label: "datetime",
},
{
value: "singleId",
label: "singleId",
},
{
value: "singleName",
label: "singleName",
},
{
value: "option",
label: "option",
},
{
value: "checkbox",
label: "checkbox",
},
{
value: "radio",
label: "radio",
},
];
function getOptions(field) {
if (field === "col_type") {
return editTypeOptions;
}
}
function updateCollapse() {
if (isCollapse.value) {
isCollapse.value = false;
leftSize.value = 200;
} else {
isCollapse.value = true;
leftSize.value = 0;
}
}
async function handleTreeLoad(node, resolve) {
try {
const { level: nodeLevel, data: nodeData } = node;
if (nodeLevel === 0) {
resolve([
{
b_id: "root",
mc_b: "全部分类",
children: [],
isLeaf: false,
},
]);
return;
}
const currentLevel = nodeLevel - 1;
let sql = "";
if (currentLevel === 0) {
sql = `SELECT * FROM s_module_bmfl WHERE js='1' AND b_canuse='1' ORDER BY b_xh`;
} else {
if (!nodeData) {
resolve([]);
return;
}
const parentField = `bm_${currentLevel}_b`;
const parentCondition = ` AND ${parentField}='${nodeData.b_id}'`;
const childLevel = currentLevel + 1;
sql = `
SELECT s_module_bmfl.*, s_module.b_id AS b_moduleid
FROM s_module_bmfl
LEFT JOIN s_module ON s_module.b_cate_id = s_module_bmfl.b_id
WHERE s_module_bmfl.b_canuse='1'
AND js='${childLevel}'
${parentCondition}
AND s_module_bmfl.b_canuse='1'
ORDER BY b_xh
`;
}
const res = await loadDataBySqlApi(sql);
if (res.success) {
resolve(res.data);
} else {
resolve([]);
}
} catch (err) {
console.error(err);
resolve([]);
}
}
async function handleTreeNodeClick(nodeData) {
if (!nodeData || nodeData.b_id === "root" || !nodeData.b_moduleid) return;
currentNode.value = nodeData;
loading.value = true;
try {
const res = await loadDataApi("s_module", `b_id = '${nodeData.b_moduleid}'`);
if (res.success) {
currentModule.value = res.data[0] || null;
if (currentModule.value?.b_ViewTable) {
const viewTable = currentModule.value?.b_ViewTable;
await loadDatas(viewTable);
}
}
} catch (err) {
console.error("加载模块或列失败", err);
} finally {
loading.value = false;
}
}
// 加载数据
async function loadDatas(viewName) {
if (!viewName) {
return;
}
const res = await loadAllColumnsApi(viewName);
if (res.success) {
tableData.value = res.data;
}
}
// 编辑关闭事件
async function handleEditClosed({ row, rowIndex, column, columnIndex }) {
const $table = tableRef.value;
if ($table) {
await handleSaveRow(row);
}
}
// 编辑激活事件
function handleEditActivated({ row }) {
const $table = tableRef.value;
if ($table) {
oldRowData = JSON.parse(JSON.stringify(row));
}
}
// 选中行事件
function handleCurrentRowChange({ newValue }) {
currentRow.value = newValue;
}
// 保存
function handleSaveRow(row) {
if (!row?.b_id) return;
const diffRowResult = diffObject(row, oldRowData, ["b_id"], []);
if (!diffRowResult.isChanged) {
return;
}
const saveData = [
{
tableName: "s_columnLib",
keyField: "b_id",
inserts: [],
updates: [diffRowResult.result],
deletes: [],
log: "0",
user: "0",
},
];
saveObjectApi(saveData).then((res) => {
if (res.success) {
ElMessage.success("保存成功");
}
});
}
// 检查
function handleCheckColumns() {
if (!currentModule.value) {
return;
}
const viewName = currentModule.value.b_ViewTable || "";
if (!viewName) {
return;
}
loading.value = true;
checkColumnsApi(viewName)
.then(async (res) => {
if (res.success) {
ElMessage.success("检查成功");
await loadDatas(viewName);
}
})
.finally(() => {
loading.value = false;
});
}
</script>
<template>
<div class="g3-wrapper">
<el-splitter>
<el-splitter-panel :size="leftSize" :min="0" :max="260">
<div class="g3-wrapper-left">
<div class="tree-header">
<el-text>模块名</el-text>
<div class="tree-options"></div>
</div>
<div class="tree-container">
<el-scrollbar style="flex: 1">
<el-tree
lazy
highlight-current
node-key="b_id"
:data="treeData"
:props="treeProps"
:load="handleTreeLoad"
:default-expanded-keys="['root']"
@node-click="handleTreeNodeClick"
/>
</el-scrollbar>
</div>
</div>
</el-splitter-panel>
<el-splitter-panel style="margin-left: 8px">
<div class="g3-wrapper-right">
<div class="content">
<div class="content-head">
<div class="content-head-left">
<el-button type="primary" :disabled="!isSelectedNode" @click="handleCheckColumns"
>检查</el-button
>
<el-button type="primary" :disabled="!isSelectedNode">浏览栏位预览</el-button>
<el-button type="primary" :disabled="!isSelectedNode">编辑栏位预览</el-button>
<el-button type="primary" :disabled="!isSelectedNode">属性预览</el-button>
<el-button type="primary">修改标签</el-button>
<el-button type="primary" :disabled="!isSelectedNode" @click="showSql = !showSql">
SQL语句
</el-button>
</div>
<div class="content-head-right">
<el-input placeholder="请输入关键词搜索" />
<el-button type="primary">搜索</el-button>
</div>
</div>
<div class="content-table">
<vxe-table
ref="tableRef"
height="100%"
:data="tableData"
:loading="loading"
:row-config="{
useKey: true,
keyField: 'col_FieldName',
isCurrent: true,
}"
:column-config="{
resizable: true,
useKey: true,
}"
:edit-config="{
trigger: 'click',
mode: 'row',
autoClear: false,
showStatus: false,
showIcon: false,
}"
:scroll-x="{
gt: 0,
enabled: true,
}"
:scroll-y="{
gt: 0,
enabled: true,
}"
show-overflow
show-header-overflow
@current-row-change="handleCurrentRowChange"
@edit-closed="handleEditClosed"
@edit-activated="handleEditActivated"
>
<vxe-column type="seq" width="50" fixed="left" />
<vxe-column
v-for="column in columns"
:key="column.prop"
:field="column.prop"
:title="column.label"
:width="column.width"
align="center"
sortable
:edit-render="{ autoFocus: true }"
:fixed="column.fixed"
>
<template #default="{ row }">
<ElCheckbox
v-if="column.type === 'checkbox'"
true-value="1"
false-value="0"
:checked="row[column.prop] === '1'"
/>
<template v-else>
{{ row[column.prop] }}
</template>
</template>
<template #edit="{ row }">
<ElCheckbox
v-if="column.type === 'checkbox'"
v-model="row[column.prop]"
true-value="1"
false-value="0"
/>
<el-select
v-else-if="column.type === 'option'"
v-model="row[column.prop]"
size="small"
placeholder=" "
>
<el-option
v-for="item in getOptions(column.prop)"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<ElInput
v-else-if="column.type === 'input'"
v-model="row[column.prop]"
size="small"
/>
<template v-else>
{{ row[column.prop] }}
</template>
</template>
</vxe-column>
</vxe-table>
</div>
</div>
</div>
</el-splitter-panel>
</el-splitter>
<PreviewSql v-model="showSql" :data="tableData" :viewtable="currentModule?.b_ViewTable" />
</div>
</template>
<style lang="scss" scoped>
@use "@/styles/mixins.scss" as *;
.g3-wrapper {
width: 100%;
height: 100%;
display: flex;
align-items: center;
:deep(.el-splitter-bar__dragger-horizontal::after),
:deep(.el-splitter-bar__dragger-horizontal::before) {
width: 1px;
}
:deep(.el-splitter-bar__dragger::after),
:deep(.el-splitter-bar__dragger::before) {
background-color: #f2f6fc;
}
}
.g3-wrapper-left {
height: 100%;
width: 100%;
background-color: #fff;
.tree-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 40px;
padding: 0 10px;
border-bottom: 1px solid #f2f6fc;
}
.tree-options {
display: flex;
align-items: center;
.item {
display: flex;
justify-content: center;
align-items: center;
list-style: none;
margin-left: 5px;
cursor: pointer;
border-radius: 6px;
font-size: 16px;
height: 26px;
width: 26px;
color: #333;
transition: background-color 0.3s ease;
&:hover {
background-color: #f5f7fa;
}
}
}
.tree-container {
height: calc(100% - 40px);
padding: 10px;
display: flex;
flex-direction: column;
}
}
.g3-wrapper-right {
flex: 1;
transition: width 0.3s;
height: 100%;
display: flex;
flex-direction: column;
background-color: #fff;
.head {
display: flex;
align-items: center;
justify-content: space-between;
height: 40px;
padding: 0 10px;
border-bottom: 1px solid #f2f6fc;
flex-shrink: 0;
.options {
display: flex;
align-items: center;
.item {
display: flex;
justify-content: center;
align-items: center;
list-style: none;
margin-left: 5px;
border-radius: 6px;
font-size: 16px;
height: 26px;
width: 26px;
color: #333;
transition: background-color 0.3s ease;
}
.item-bg {
cursor: pointer;
background-color: #f5f7fa;
}
}
}
.content {
padding: 10px;
display: flex;
flex-direction: column;
min-width: 0;
height: 100%;
.content-head {
display: flex;
align-items: center;
justify-content: space-between;
.content-head-left {
display: flex;
@include flexGapWrap(4px, 8px);
}
.content-head-right {
display: flex;
@include flexGapWrap(4px, 8px);
flex-wrap: nowrap;
min-width: 200px;
}
}
.content-table {
margin-top: 8px;
flex: 1;
}
}
}
</style>
Whitespace-only changes.
@@ -0,0 +1,71 @@
<template>
<el-dialog v-bind="$attrs" title="Sql预览" width="1000px" class="dialog" @open="initData">
<div class="sql-preview">
{{ sqlStr }}
</div>
</el-dialog>
</template>
<script setup>
import { ref } from "vue";
const props = defineProps({
data: {
type: null,
},
viewtable: {
type: null,
},
});
const sqlStr = ref("");
function initData() {
if (!props.viewtable) return;
const vrows = props.data || [];
const sqlArr = [];
// 删除语句
const deleteSql = `DELETE FROM s_columnlib WHERE col_TableName='${props.viewtable}';`;
sqlArr.push(deleteSql);
// 插入语句
vrows.forEach((row) => {
const insertSql =
"INSERT INTO s_columnlib(col_TableName,col_FieldName,col_Caption,col_Width,col_Visible,col_Position," +
"col_ShowSummary,col_BandIndex,col_AllowNull,col_AllowRepeat,col_DefaultValue,col_ReadOnly,col_Color," +
"col_CanSearch,col_SearchOrder,col_NeedReserve,col_sorted,col_DisplayFormat,col_type,col_datatype,col_foot)";
const valueSql =
`VALUES('${props.viewtable}', '${row.col_FieldName}', '${row.col_Caption}', '${row.col_Width}', '${row.col_Visible}', '${row.col_Position}', ` +
`'${row.col_ShowSummary}', '${row.col_BandIndex}', '${row.col_AllowNull}', '${row.col_AllowRepeat}', '${row.col_DefaultValue}', '${row.col_ReadOnly}', '${row.col_Color}', ` +
`'${row.col_CanSearch}', '${row.col_SearchOrder}', '${row.col_NeedReserve}', '${row.col_sorted}', '${row.col_DisplayFormat}', '${row.col_type}', '${row.col_datatype}', '${row.col_foot}');`;
sqlArr.push(insertSql);
sqlArr.push(valueSql);
});
// 合并为字符串
sqlStr.value = sqlArr.join("\n");
}
</script>
<style scoped>
.dialog-content {
display: flex;
gap: 16px;
}
.sql-preview {
width: 100%;
height: 500px;
overflow: auto;
white-space: pre-wrap;
word-break: break-all;
font-family: monospace;
padding: 8px;
border: 1px solid #e0e0e0;
background-color: #fafafa;
box-sizing: border-box;
}
</style>
@@ -0,0 +1,7 @@
<script lang="js" setup></script>
<template>
<div class=""></div>
</template>
<style lang="scss" scoped></style>
@@ -0,0 +1,11 @@
<script lang="js" setup>
const router = useRouter();
</script>
<template>
<div class="">
test-detail
</div>
</template>
<style lang="scss" scoped></style>
@@ -0,0 +1,7 @@
<script lang="js" setup></script>
<template>
<div class=""></div>
</template>
<style lang="scss" scoped></style>