@ -0,0 +1,7 @@ |
|||
namespace AuthServer.Host.Services.Token; |
|||
|
|||
public class LoginModel |
|||
{ |
|||
public string UserName { get; set;} |
|||
public string Password { get; set;} |
|||
} |
@ -0,0 +1,63 @@ |
|||
using IdentityModel.Client; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using System.Net.Http; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.Account.Web.Pages.Account; |
|||
using Volo.Abp.Application.Services; |
|||
using Microsoft.AspNetCore.Http; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Configuration; |
|||
|
|||
namespace AuthServer.Host.Services.Token; |
|||
|
|||
[Route("/api/[controller]/[action]")]
|
|||
public class TokenService : ApplicationService |
|||
{ |
|||
private readonly IHttpContextAccessor _httpContextAccessor; |
|||
private readonly IHttpClientFactory _httpClientFactory; |
|||
private readonly ILogger<TokenService> _logger; |
|||
private readonly IConfiguration _configuration; |
|||
public TokenService(IHttpContextAccessor httpContextAccessor, IHttpClientFactory httpClientFactory, IConfiguration configuration, ILogger<TokenService> logger) |
|||
{ |
|||
this._httpContextAccessor = httpContextAccessor; |
|||
this._httpClientFactory = httpClientFactory; |
|||
this._configuration = configuration; |
|||
this._logger = logger; |
|||
} |
|||
|
|||
[HttpPost("token")] |
|||
[AllowAnonymous] |
|||
public async Task<IActionResult> CreateAsync(LoginModel model) |
|||
{ |
|||
var address = _configuration["AuthServer:Authority"]; |
|||
var clientId = _configuration["AuthServer:ClientId"]; |
|||
var clientSecret = _configuration["AuthServer:ClientSecret"]; |
|||
|
|||
var result = await _httpClientFactory.CreateClient().RequestPasswordTokenAsync(new PasswordTokenRequest |
|||
{ |
|||
Address = $"{address.TrimEnd('/')}/connect/token", |
|||
GrantType = "password", |
|||
ClientId = clientId, |
|||
ClientSecret = clientSecret, |
|||
UserName = model.UserName, |
|||
Password = model.Password |
|||
}).ConfigureAwait(false); |
|||
|
|||
return new JsonResult(new |
|||
{ |
|||
result.TokenType, |
|||
result.AccessToken, |
|||
result.ExpiresIn, |
|||
result.RefreshToken, |
|||
result.Scope, |
|||
result.HttpStatusCode, |
|||
result.Error, |
|||
result.HttpErrorReason, |
|||
result.ErrorDescription, |
|||
result.ErrorType, |
|||
result.Exception?.Message, |
|||
Exception = result.Exception?.ToString() |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,25 @@ |
|||
{ |
|||
"root": true, |
|||
"rules": { |
|||
"import/extensions": [ |
|||
2, |
|||
"ignorePackages", |
|||
{ |
|||
"js": "never", |
|||
"jsx": "never", |
|||
"ts": "never", |
|||
"tsx": "never" |
|||
} |
|||
], |
|||
"sort-imports": [ |
|||
"error", |
|||
{ |
|||
"ignoreCase": false, |
|||
"ignoreDeclarationSort": false, |
|||
"ignoreMemberSort": false, |
|||
"memberSyntaxSortOrder": ["none", "all", "multiple", "single"], |
|||
"allowSeparatedGroups": false |
|||
} |
|||
] |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"printWidth": 120, |
|||
"tabWidth": 2, |
|||
"useTabs": false, |
|||
"semi": true, |
|||
"ssingleQuote": true, |
|||
"squoteProps": "as-needed", |
|||
"sjsxSingleQuote": false, |
|||
"strailingComma": "all", |
|||
"sbracketSpacing": true, |
|||
"sjsxBracketSameLine": false, |
|||
"sarrowParens": "always", |
|||
"srangeStart": 0, |
|||
"srangeEnd": "Infinity", |
|||
"srequirePragma": false, |
|||
"sinsertPragma": false, |
|||
"sproseWrap": "preserve", |
|||
"shtmlWhitespaceSensitivity": "css", |
|||
"svueIndentScriptAndStyle": false, |
|||
"endOfLine": "lf" |
|||
} |
@ -0,0 +1,5 @@ |
|||
{ |
|||
"recommendations": [ |
|||
"Vue.volar", |
|||
] |
|||
} |
@ -0,0 +1,7 @@ |
|||
{ |
|||
"search.exclude": { |
|||
"lib": true |
|||
}, |
|||
"editor.formatOnSave": true, |
|||
"liveServer.settings.port": 9527 |
|||
} |
@ -0,0 +1,169 @@ |
|||
import { get, post } from "../request/index.js"; |
|||
|
|||
async function getLocalizationAsync() { |
|||
// const url = "abp/application-configuration";
|
|||
// const data = (await get(url, null, null, true, true)).data;
|
|||
return { |
|||
options: [ |
|||
{ |
|||
value: "zh", |
|||
label: "中文", |
|||
}, |
|||
{ |
|||
value: "en", |
|||
label: "English", |
|||
}, |
|||
], |
|||
locale: "zh", |
|||
messages: { |
|||
zh: { |
|||
application: "北京北汽模塑-SAS结算分析系统", |
|||
copyright: "长春市闻荫科技有限公司 ©2023", |
|||
test: "测试", |
|||
compareAttribute: "{0}”和{1}不匹配", |
|||
fileExtensionsAttribute: "{0}只接受一下扩展名的文件: {1}", |
|||
maxLengthAttribute: "{0}的最大长度为 {1}", |
|||
minLengthAttribute: "{0}的最小长度为 {1}", |
|||
rangeAttribute: "{0}必需在 {1} 和 {2} 之间", |
|||
regularExpressionAttribute: "{0}”必需匹配{1}", |
|||
requiredAttribute: "{0}不能为空", |
|||
stringLengthAttribute: "{0}的最大长度为 {1}", |
|||
stringLengthAttributeIncludingMinimum: "{0}的长度在 {2} 和 {1} 之间", |
|||
dataTypeAttribute_CreditCard: "{0}不是有效的信用卡号码", |
|||
dataTypeAttribute_EmailAddress: "{0}不是有效的 Email 地址", |
|||
dataTypeAttribute_PhoneNumber: "{0}不是有效的手机号码", |
|||
dataTypeAttribute_Url: "{0}不是有效的 Url", |
|||
dataTypeAttribute_Upload: "{0}的扩展名必须为:{1}", |
|||
dataTypeAttribute_DateTime: "{0}不是有效的日期格式", |
|||
customValidationAttribute: "{0}验证失败", |
|||
validationAttribute: "{0}验证失败", |
|||
true: "是", |
|||
false: "否", |
|||
select: "选择", |
|||
confirm: "确定", |
|||
reset: "重置", |
|||
rowIndex: "行号", |
|||
name: "名称", |
|||
number: "编号", |
|||
value: "值", |
|||
order: "序号", |
|||
isDisabled: "禁用", |
|||
properties: "属性", |
|||
parentId: "上级", |
|||
lockoutEnabled: "启用锁定", |
|||
lockoutEnd: "锁定截止", |
|||
accessFailedCount: "登录失败次数", |
|||
isSystem: "系统内置", |
|||
isReadonly: "只读", |
|||
audit: "审计", |
|||
selectAll: "全选", |
|||
selectInverse: "反选", |
|||
filter: "过滤", |
|||
createdOn: "创建时间", |
|||
createdBy: "创建人", |
|||
updatedOn: "修改时间", |
|||
updatedBy: "修改人", |
|||
deletedOn: "删除时间", |
|||
deletedBy: "删除人", |
|||
concurrencyStamp: "并发戳", |
|||
operations: "操作", |
|||
disabled: "已禁用", |
|||
displayOrder: "序号", |
|||
isDeleted: "已删除", |
|||
path: "路径", |
|||
method: "方法", |
|||
isTop: "顶部", |
|||
htmlClass: "class", |
|||
internalPath: "内部路径", |
|||
component: "组件", |
|||
serverTime: "服务器时间", |
|||
osArchitecture: "系统架构", |
|||
osDescription: "操作系统", |
|||
processArchitecture: "进程架构", |
|||
tip: "提示", |
|||
cancel: "操作取消", |
|||
index: "查询", |
|||
details: "详情", |
|||
create: "新建", |
|||
update: "更新", |
|||
import: "导入", |
|||
export: "导出", |
|||
remove: "移除", |
|||
restore: "还原", |
|||
delete: "删除", |
|||
authenticate: "验证", |
|||
loginModel: "登录", |
|||
login: "登录", |
|||
logout: "注销", |
|||
confirmLogout: "确认退出?", |
|||
register: "注册", |
|||
userName: "用户名", |
|||
password: "密码", |
|||
email: "邮箱", |
|||
emailConfirmed: "邮箱已确认", |
|||
rememberMe: "记住我", |
|||
resetPassword: "重置密码", |
|||
userCenter: "用户中心", |
|||
avatar: "头像", |
|||
tenant: "租户", |
|||
connectionString: "连接字符串", |
|||
tenantId: "租户", |
|||
tenants: "租户管理", |
|||
identity: "认证中心", |
|||
systemManagement: "基础数据", |
|||
roleId: "角色", |
|||
permissionId: "权限", |
|||
userRoles: "用户角色", |
|||
enableColumnLimit: "列权限", |
|||
enableRowLimit: "行权限", |
|||
rolePermissions: "角色权限", |
|||
departmentId: "部门", |
|||
cron: "定时器", |
|||
icon: "图标", |
|||
type: "类型", |
|||
isExternal: "外链", |
|||
isHidden: "隐藏", |
|||
redirect: "跳转", |
|||
columns: "列", |
|||
identityModule: "系统管理", |
|||
user: "用户", |
|||
role: "角色", |
|||
permission: "权限", |
|||
department: "部门", |
|||
post: "岗位", |
|||
dict: "字典", |
|||
systemMonitor: "系统监控", |
|||
monitor: "服务监控", |
|||
monitorModule: "系统监控", |
|||
jobItem: "定时任务", |
|||
captcha: "验证码", |
|||
captchaExpired: "验证码已过期", |
|||
captchaError: "验证码错误", |
|||
dictionaryItem: "数据字典", |
|||
userLogin: "登录历史", |
|||
connectionId: "连接Id", |
|||
isOnline: "在线", |
|||
heartbeat: "心跳", |
|||
userAgent: "用户代理", |
|||
}, |
|||
en: { |
|||
application: "WTA Framework", |
|||
copyright: "all rights reserved © copyright", |
|||
test: "test", |
|||
login: "Login", |
|||
logout: "Logout", |
|||
confirmLogout: "Confirm Logout?", |
|||
register: "Register", |
|||
tip: "Tip", |
|||
cancel: "Cancel", |
|||
userName: "User Name", |
|||
password: "Password", |
|||
rememberMe: "Remember Me", |
|||
resetPassword: "Reset Password", |
|||
userCenter: "User Center", |
|||
}, |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
export { getLocalizationAsync }; |
@ -0,0 +1,80 @@ |
|||
import router from "../router/index.js"; |
|||
import { get, post } from "../request/index.js"; |
|||
import jwt_decode from "../lib/jwt-decode/jwt-decode.esm.js"; |
|||
import qs from "../lib/qs/shim.js"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import { refreshRouter } from "../router/index.js"; |
|||
import Enumerable from "linq"; |
|||
import { connection } from "../signalr/index.js"; |
|||
|
|||
const isLogin = async () => { |
|||
const appStore = useAppStore(); |
|||
// 有 token,判断是否过期,失败设置 token 为 null
|
|||
if (appStore.token) { |
|||
const exp = new Date(jwt_decode(appStore.token).exp * 1000); |
|||
if (exp > new Date()) { |
|||
return true; |
|||
} else { |
|||
appStore.token = null; |
|||
} |
|||
} |
|||
return false; |
|||
}; |
|||
|
|||
const login = async (data) => { |
|||
const url = "connect-token"; |
|||
const appStore = useAppStore(); |
|||
const result = await post(url, data, { headers: { "Content-Type": "application/x-www-form-urlencoded" } }, true); |
|||
if (!result.errors) { |
|||
appStore.token = result.data.access_token; |
|||
setRefreshToken(result.data.refresh_token); |
|||
appStore.user = await getUser(); |
|||
await refreshRouter(); |
|||
const redirect = router.currentRoute.value.query?.redirect ?? "/"; |
|||
router.push(redirect); |
|||
} |
|||
return result; |
|||
}; |
|||
|
|||
const logout = () => { |
|||
const appStore = useAppStore(); |
|||
appStore.token = null; |
|||
removeRefreshToken(); |
|||
router.push({ path: "/login", query: { redirect: router.currentRoute.value.fullPath } }); |
|||
}; |
|||
|
|||
const getUser = async () => { |
|||
const result = await get("abp/application-configuration"); |
|||
const data = result.data; |
|||
const user = {}; |
|||
user.name = data.currentUser.userName; |
|||
user.email = data.currentUser.email; |
|||
user.roles = data.currentUser.roles; |
|||
const menus = (await get("base/role-menus")).data; |
|||
user.permissions = menus.items; |
|||
return user; |
|||
}; |
|||
|
|||
const hasPermission = (to) => { |
|||
const appStore = useAppStore(); |
|||
const permission = to.meta?.permission; |
|||
if (permission) { |
|||
const hasPermission = Enumerable.from(appStore.user.permissions).any((o) => o.number === permission); |
|||
return hasPermission; |
|||
} else { |
|||
return true; |
|||
} |
|||
}; |
|||
|
|||
const refreshTokenKey = "refresh_token"; |
|||
|
|||
const getRefreshToken = () => localStorage.getItem(refreshTokenKey); |
|||
|
|||
const setRefreshToken = (refreshToken) => localStorage.setItem(refreshTokenKey, refreshToken); |
|||
|
|||
const removeRefreshToken = () => { |
|||
localStorage.removeItem(refreshTokenKey); |
|||
connection.stop(); |
|||
}; |
|||
|
|||
export { isLogin, login, logout, getUser, hasPermission }; |
@ -0,0 +1,27 @@ |
|||
import html from "html"; |
|||
import { ElConfigProvider } from "element-plus"; |
|||
import zh from "./lib/element-plus/locale/zh-cn.min.mjs"; |
|||
import en from "./lib/element-plus/locale/en.min.mjs"; |
|||
import { Suspense, reactive, onMounted } from "vue"; |
|||
|
|||
export default { |
|||
components: { ElConfigProvider, Suspense }, |
|||
template: html`<suspense>
|
|||
<el-config-provider :locale="localeMap.get($i18n.locale)"> |
|||
<router-view></router-view> |
|||
</el-config-provider> |
|||
<template #fallback> Loading... </template> |
|||
</suspense>`, |
|||
setup() { |
|||
const localeMap = reactive( |
|||
new Map([ |
|||
["zh", zh], |
|||
["en", en], |
|||
]) |
|||
); |
|||
onMounted(() => document.querySelector("#loading.loading").classList.remove("loading")); |
|||
return { |
|||
localeMap, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,18 @@ |
|||
Markdown |
|||
======== |
|||
|
|||
## flowchart |
|||
|
|||
```mermaid |
|||
flowchart LR |
|||
Start --> Stop |
|||
``` |
|||
|
|||
## highlight |
|||
|
|||
```javascript |
|||
function (){ |
|||
let a=1; |
|||
alert(a); |
|||
} |
|||
``` |
After Width: | Height: | Size: 237 B |
After Width: | Height: | Size: 471 B |
After Width: | Height: | Size: 500 B |
After Width: | Height: | Size: 283 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 595 B |
After Width: | Height: | Size: 287 B |
After Width: | Height: | Size: 942 B |
After Width: | Height: | Size: 945 B |
After Width: | Height: | Size: 463 B |
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 279 B |
After Width: | Height: | Size: 558 B |
After Width: | Height: | Size: 856 B |
After Width: | Height: | Size: 594 B |
After Width: | Height: | Size: 577 B |
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,37 @@ |
|||
import { nextTick, ref } from 'vue'; |
|||
import VCharts from 'vue-echarts'; |
|||
|
|||
const template = `<VCharts
|
|||
v-if="renderChart" |
|||
:option="options" |
|||
:autoresize="autoresize" |
|||
:style="{ width, height }" |
|||
/>`; |
|||
|
|||
export default { |
|||
template, |
|||
components: { VCharts }, |
|||
props: { |
|||
options: { |
|||
default: {}, |
|||
}, |
|||
autoresize: { |
|||
default: true, |
|||
}, |
|||
width: { |
|||
default: '100%', |
|||
}, |
|||
height: { |
|||
default: '100%', |
|||
}, |
|||
}, |
|||
setup() { |
|||
const renderChart = ref(false); |
|||
nextTick(() => { |
|||
renderChart.value = true; |
|||
}); |
|||
return { |
|||
renderChart, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,93 @@ |
|||
import html from "html"; |
|||
import { ref, reactive, watch } from "vue"; |
|||
import { dayjs } from "element-plus"; |
|||
|
|||
export default { |
|||
template: html` |
|||
<template v-if="getDisabled()"> |
|||
<template v-if="model[prop]!==null"> |
|||
<el-switch disabled v-model="model[prop]" type="checked" v-if="schema.type==='boolean'" /> |
|||
<template v-else-if="schema.format==='datetime'">{{dayjs(model[prop]).format('YYYY-MM-DD HH:mm:ss')}}</template> |
|||
<template v-else-if="schema.format==='date'">{{dayjs(model[prop]).format('YYYY-MM-DD')}}</template> |
|||
<template v-else>{{model[prop]}}</template> |
|||
</template> |
|||
</template> |
|||
<template v-else> |
|||
<template v-if="getInput(schema)==='select'"> |
|||
<el-select |
|||
v-model="model[prop]" |
|||
:placeholder="$t('select')" |
|||
:multiple="!!schema.multiple" |
|||
clearable |
|||
style="width:100%" |
|||
> |
|||
<el-option v-for="item in schema.options" :key="item.value" :label="item.label" :value="item.value" /> |
|||
</el-select> |
|||
</template> |
|||
<el-input |
|||
:disabled="getDisabled()" |
|||
:placeholder="schema.title" |
|||
v-model="model[prop]" |
|||
type="number" |
|||
v-else-if="schema.type==='number'" |
|||
/> |
|||
<el-input-number |
|||
:disabled="getDisabled()" |
|||
:placeholder="schema.title" |
|||
v-model="model[prop]" |
|||
:precision="0" |
|||
v-else-if="schema.type==='integer'" |
|||
/> |
|||
<template v-else-if="schema.type==='boolean'"> |
|||
<el-select :disabled="getDisabled()" v-model="model[prop]" :placeholder="schema.title" v-if="schema.nullable"> |
|||
<el-option prop="select" :value="null" :label="$t('select')" /> |
|||
<el-option prop="true" :value="true" :label="$t('true')" /> |
|||
<el-option prop="false" :value="false" :label="$t('false')" /> |
|||
</el-select> |
|||
<el-switch v-model="model[prop]" type="checked" v-else /> |
|||
</template> |
|||
<template v-else> |
|||
<el-input |
|||
:disabled="getDisabled()" |
|||
:placeholder="schema.title" |
|||
v-model="model[prop]" |
|||
type="password" |
|||
show-password |
|||
v-if="schema.format==='password'" |
|||
/> |
|||
<el-input :disabled="getDisabled()" :placeholder="schema.title" v-model="model[prop]" type="text" v-else /> |
|||
</template> |
|||
</template> |
|||
`,
|
|||
props: ["modelValue", "schema", "prop", "isReadOnly"], |
|||
emit: ["update:modelValue"], |
|||
async setup(props, context) { |
|||
const model = reactive(props.modelValue); |
|||
watch(model, (value) => { |
|||
context.emit("update:modelValue", value); |
|||
}); |
|||
/*start*/ |
|||
const getDisabled = () => { |
|||
if (props.isReadOnly && props.isReadOnly === true) { |
|||
return true; |
|||
} |
|||
if (props.schema.displayOnly) { |
|||
return true; |
|||
} |
|||
if (props.mode === "update" && props.schema.addOnly) { |
|||
return true; |
|||
} |
|||
return false; |
|||
}; |
|||
const getInput = (schema) => { |
|||
return schema.input ?? schema.type; |
|||
}; |
|||
/*end*/ |
|||
return { |
|||
model, |
|||
getDisabled, |
|||
getInput, |
|||
dayjs, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,94 @@ |
|||
import html from "html"; |
|||
import { ref, reactive, watch } from "vue"; |
|||
import AppFormInput from "./form-input.js"; |
|||
|
|||
export default { |
|||
name: "formItem", |
|||
components: { AppFormInput }, |
|||
template: html` |
|||
<template v-if="showItem()"> |
|||
<template v-if="schema.type==='object'"></template> |
|||
<template v-if="schema.type!=='array'||(schema.items.type!=='object'&&schema.items.type!=='array')"> </template> |
|||
<el-form-item |
|||
:title="getProp(prop)" |
|||
:label="schema.title" |
|||
:prop="getProp(prop)" |
|||
:rules="getRules(parentSchema,schema,model)" |
|||
:error="mode==='query'?null:getError(prop)" |
|||
> |
|||
<app-form-input :schema="schema" :prop="prop" v-model="model" :isReadOnly="mode==='details'" /> |
|||
</el-form-item> |
|||
</template> |
|||
</template> |
|||
`,
|
|||
props: ["modelValue", "mode", "parentSchema", "schema", "prop", "errors"], |
|||
emit: ["update:modelValue"], |
|||
async setup(props, context) { |
|||
const model = reactive(props.modelValue); |
|||
watch(model, (value) => { |
|||
context.emit("update:modelValue", value); |
|||
}); |
|||
/*start*/ |
|||
const showItem = () => { |
|||
if (props.schema.hidden) { |
|||
return false; |
|||
} |
|||
if (props.schema.readOnly && (props.mode === "query" || props.mode === "create" || props.mode === "update")) { |
|||
return false; |
|||
} |
|||
return true; |
|||
}; |
|||
//
|
|||
const getProp = (prop) => { |
|||
return prop; |
|||
}; |
|||
//
|
|||
const getError = (prop) => { |
|||
return props.errors[prop]; |
|||
}; |
|||
//
|
|||
const getRules = (parentSchema, property, data) => { |
|||
if (props.mode === "query" || props.mode === "details" || !property.rules) { |
|||
return null; |
|||
} |
|||
const rules = [...(Array.isArray(property.rules) ? property.rules : [property.rules])].map((o) => |
|||
JSON.parse(JSON.stringify(o)) |
|||
); |
|||
Object.values(rules).forEach((rule) => { |
|||
rule.data = data; |
|||
rule.schema = parentSchema; |
|||
rule.title = rule.title ?? property.title; |
|||
rule.type = property.type; |
|||
if (rule.validator) { |
|||
rule.validator = validators[rule.validator]; |
|||
} |
|||
if (!rule.message) { |
|||
if (rule.required) { |
|||
rule.message = format(schema.messages.required, property.title); |
|||
} else if (rule.pattern) { |
|||
rule.message = format(schema.messages.pattern, property.title); |
|||
} else if (property.type === "string" || property.type === "number" || property.type === "array") { |
|||
if (rule.len) { |
|||
rule.message = format(schema.messages[property.type].len, property.title, rule.len); |
|||
} else if (rule.min) { |
|||
rule.message = format(schema.messages[property.type].min, property.title, rule.min); |
|||
} else if (rule.max) { |
|||
rule.message = format(schema.messages[property.type].max, property.title, rule.max); |
|||
} else if (rule.range) { |
|||
rule.message = format(schema.messages[property.type].range, property.title, rule.range); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
return rules; |
|||
}; |
|||
/*end*/ |
|||
return { |
|||
model, |
|||
showItem, |
|||
getProp, |
|||
getError, |
|||
getRules, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,75 @@ |
|||
import html from "html"; |
|||
import { ref, reactive, watch } from "vue"; |
|||
import AppFormItem from "./form-item.js"; |
|||
|
|||
export default { |
|||
components: { AppFormItem }, |
|||
name: "AppForm", |
|||
template: html`<el-form ref="formRef" :model="model" label-width="auto">
|
|||
<template v-for="(value, prop) in schema.properties"> |
|||
<app-form-item |
|||
:parentSchema="schema" |
|||
:schema="value" |
|||
v-model="model" |
|||
:prop="prop" |
|||
:mode="mode" |
|||
:errors="errors" |
|||
/> |
|||
</template> |
|||
<slot name="items"></slot> |
|||
<el-form-item v-if="!hideButton"> |
|||
<template #label></template> |
|||
<el-button type="primary" @click="submit" :disabled="loading"><slot>$t('confirm')</slot></el-button> |
|||
</el-form-item> |
|||
</el-form>`, |
|||
props: ["modelValue", "schema", "action", "hideButton", "isQueryForm", "mode"], |
|||
emits: ["update:modelValue", "submit"], |
|||
setup(props, context) { |
|||
// init
|
|||
const model = reactive(props.modelValue); |
|||
watch(model, (value) => { |
|||
context.emit("update:modelValue", value); |
|||
}); |
|||
// ref
|
|||
const formRef = ref(null); |
|||
const loading = ref(false); |
|||
//
|
|||
const errors = ref({}); |
|||
// reset
|
|||
const reset = () => { |
|||
formRef.value.resetFields(); |
|||
}; |
|||
// validate
|
|||
const validate = async () => { |
|||
return formRef.value.validate(); |
|||
}; |
|||
// submit
|
|||
const submit = async () => { |
|||
try { |
|||
//const valid = await validate();
|
|||
//if (valid) {
|
|||
loading.value = true; |
|||
context.emit("submit", (serverErrors) => { |
|||
if (serverErrors) { |
|||
errors.value = serverErrors; |
|||
} |
|||
}); |
|||
//}
|
|||
} catch (error) { |
|||
console.error(error); |
|||
} finally { |
|||
loading.value = false; |
|||
} |
|||
}; |
|||
// expose
|
|||
context.expose({ validate, reset }); |
|||
return { |
|||
model, |
|||
formRef, |
|||
loading, |
|||
errors, |
|||
reset, |
|||
submit, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,34 @@ |
|||
import { onMounted, ref } from "vue"; |
|||
|
|||
const template = `<component v-if="name.indexOf('ep-')===0" :is="name" /> <v-else g v-html="svg" /> `; |
|||
|
|||
export default { |
|||
props: { |
|||
name: { |
|||
default: "file", |
|||
}, |
|||
}, |
|||
template, |
|||
setup(props) { |
|||
const svg = ref(""); |
|||
onMounted(async () => { |
|||
if (props.name.indexOf("ep-") !== 0) { |
|||
try { |
|||
const response = await fetch(`./assets/icons/${props.name}.svg`); |
|||
if (response.ok && response.status === 200) { |
|||
svg.value = await response.text(); |
|||
} |
|||
} catch (error) { |
|||
console.error(error); |
|||
} |
|||
if (!svg.value) { |
|||
const response = await fetch("./assets/icons/file.svg"); |
|||
svg.value = await response.text(); |
|||
} |
|||
} |
|||
}); |
|||
return { |
|||
svg, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,390 @@ |
|||
import html, { getProp } from "html"; |
|||
import AppForm from "../form/index.js"; |
|||
import { get, post } from "../../request/index.js"; |
|||
import { ref, reactive } from "vue"; |
|||
import { useRoute } from "vue-router"; |
|||
import { useI18n } from "vue-i18n"; |
|||
import SvgIcon from "../../components/icon/index.js"; |
|||
import { schemaToModel } from "../../utils/index.js"; |
|||
import qs from "../../lib/qs/shim.js"; |
|||
import AppFormInput from "../form/form-input.js"; |
|||
import VueOfficeExcel from "@vue-office/excel"; |
|||
import { camelCase, capitalize } from "lodash"; |
|||
|
|||
export default { |
|||
components: { AppForm, SvgIcon, AppFormInput, VueOfficeExcel }, |
|||
template: html` |
|||
<el-row> |
|||
<el-col> |
|||
<app-form |
|||
inline |
|||
mode="query" |
|||
label-position="left" |
|||
:schema="queryFromSchema" |
|||
v-model="data.query" |
|||
@submit="load" |
|||
:hideButton="true" |
|||
:isQueryForm="true" |
|||
/> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row style="padding-bottom:20px;"> |
|||
<el-col> |
|||
<template v-for="item in $route.meta.buttons"> |
|||
<el-button |
|||
:class="item.meta.htmlClass??'el-button--primary'" |
|||
v-if="item.meta.isTop" |
|||
@click="click(item,selectedRows)" |
|||
> |
|||
<el-icon v-if="item.meta.icon"><svg-icon :name="item.meta.icon" /></el-icon> |
|||
<span>{{item.meta.title}}</span> |
|||
</el-button> |
|||
</template> |
|||
<slot name="tableButtons" :rows="selectedRows"></slot> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row> |
|||
<el-col> |
|||
<el-scrollbar> |
|||
<el-table |
|||
ref="tableRef" |
|||
v-loading="tableLoading" |
|||
row-key="id" |
|||
table-layout="auto" |
|||
border |
|||
fit |
|||
:data="data.items" |
|||
@selection-change="handleSelectionChange" |
|||
@sort-change="sortChange" |
|||
:header-cell-class-name="getClass" |
|||
v-if="data.items" |
|||
> |
|||
<el-table-column fixed="left" type="selection" /> |
|||
<el-table-column type="index" :label="$t('rowIndex')"> |
|||
<template #default="scope"> {{ (data.pageIndex - 1) * data.pageSize + scope.$index + 1 }} </template> |
|||
</el-table-column> |
|||
<template v-for="(item,key) in tableSchema.items.properties"> |
|||
<template v-if="key==='properties'"> |
|||
<el-table-column :label="subKey" v-for="(subItem,subKey) in item.properties"> |
|||
<template #default="scope">{{ scope.row[key][subKey] }} </template> |
|||
</el-table-column> |
|||
</template> |
|||
<template v-else-if="item.navigation"> |
|||
<el-table-column :prop="key" :label="item.title"> |
|||
<template #default="scope">{{getProp(scope.row,item.navigation)}}</template> |
|||
</el-table-column> |
|||
</template> |
|||
<template v-else> |
|||
<template v-if="showColumn(item,key)"> |
|||
<el-table-column :prop="key" sortable="custom" :sort-orders="['descending', 'ascending', null]"> |
|||
<template #header="scope">{{item.title}}</template> |
|||
<template #default="scope"> |
|||
<app-form-input :isReadOnly="true" :schema="item" :prop="key" v-model="scope.row" /> |
|||
</template> |
|||
</el-table-column> |
|||
</template> |
|||
</template> |
|||
</template> |
|||
<slot name="columns"></slot> |
|||
<el-table-column fixed="right"> |
|||
<template #header> |
|||
<el-button @click="filterDrawer = true"> |
|||
{{$t('operations')}} |
|||
<el-icon class="el-icon--right"><ep-filter /></el-icon> |
|||
</el-button> |
|||
</template> |
|||
<template #default="scope"> |
|||
<div class="flex"> |
|||
<template v-for="item in $route.meta.buttons"> |
|||
<el-button |
|||
:class="item.meta.htmlClass??'el-button--primary'" |
|||
v-if="!item.meta.isTop" |
|||
@click="click(item,[scope.row])" |
|||
> |
|||
<el-icon v-if="item.meta.icon"><svg-icon :name="item.meta.icon" /></el-icon> |
|||
<span>{{item.meta.title}}</span> |
|||
</el-button> |
|||
</template> |
|||
<slot name="rowButtons" :rows="[scope.row]"></slot> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</el-scrollbar> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row> |
|||
<el-col> |
|||
<el-pagination |
|||
v-if="data.items&&data.pageSize<data.totalCount" |
|||
v-model:currentPage="data.pageIndex" |
|||
v-model:page-size="data.pageSize" |
|||
:total="data.totalCount" |
|||
:page-sizes="[20, 50, 100]" |
|||
class="justify-end" |
|||
:background="true" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
@size-change="onPageSizeChange" |
|||
@current-change="onPageIndexChange" |
|||
style="margin-top:20px" |
|||
/> |
|||
</el-col> |
|||
</el-row> |
|||
<el-drawer v-model="filterDrawer" destroy-on-close @close="tableRef.doLayout()"> |
|||
<template #header> <span class="el-dialog__title"> {{$t('filter')}} </span> </template> |
|||
<el-scrollbar> |
|||
<el-row> |
|||
<el-col style="max-height:calc(100vh - 180px);"> |
|||
<el-form inline> |
|||
<el-form-item> |
|||
<el-button type="primary" @click="columns.forEach(o=>o.checked=true)"> {{$t('selectAll')}} </el-button> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button type="primary" @click="columns.forEach(o=>o.checked=!o.checked)"> |
|||
{{$t('selectInverse')}} |
|||
</el-button> |
|||
</el-form-item> |
|||
<el-form-item v-for="item in columns"> |
|||
<el-checkbox v-model="item.checked" :label="item.title" size="large" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
</el-col> |
|||
</el-row> |
|||
</el-scrollbar> |
|||
|
|||
<template #footer> |
|||
<span class="dialog-footer"> |
|||
<el-button type="primary" @click="filterDrawer=false"> {{$t('confirm')}} </el-button> |
|||
</span> |
|||
</template> |
|||
</el-drawer> |
|||
<el-dialog v-model="dialogVisible" align-center destroy-on-close width="700"> |
|||
<template #header> <span class="el-dialog__title"> {{editFormTitle}} </span> </template> |
|||
<el-row> |
|||
<el-col style="max-height:calc(100vh - 180px );"> |
|||
<el-scrollbar> |
|||
<app-form |
|||
v-loading="editFormloading" |
|||
:disabled="editFormMode==='details'" |
|||
:mode="editFormMode" |
|||
ref="editFormRef" |
|||
inline |
|||
label-position="left" |
|||
:hideButton="true" |
|||
:schema="editFormSchema" |
|||
v-model="editFormModel" |
|||
v-if="editFormMode!=='import'" |
|||
/> |
|||
</el-scrollbar> |
|||
</el-col> |
|||
</el-row> |
|||
<template #footer> |
|||
<span class="dialog-footer"> |
|||
<el-button type="primary" @click="submit"> {{$t('confirm')}} </el-button> |
|||
</span> |
|||
</template> |
|||
</el-dialog> |
|||
`,
|
|||
props: ["modelValue"], |
|||
emits: ["command"], |
|||
async setup(props, context) { |
|||
const tableRef = ref(null); |
|||
const columns = ref([]); |
|||
const filterDrawer = ref(false); |
|||
const tableLoading = ref(false); |
|||
const selectedRows = ref([]); |
|||
const dialogVisible = ref(false); |
|||
const route = useRoute(); |
|||
const { t } = useI18n(); |
|||
const baseUrl = `${route.meta.path}`.substring(1); |
|||
const indexUrl = `${baseUrl}/index`; |
|||
const vm = (await get(indexUrl)).data; |
|||
const schema = vm.schema; |
|||
const data = reactive(vm.model ?? schemaToModel(schema)); |
|||
const sortColumns = ref(new Map()); |
|||
const getSortModel = (model) => { |
|||
const orderBy = model.orderBy |
|||
.split(",") |
|||
.map((o) => o.trim()) |
|||
.filter((o) => o) |
|||
.map((o) => ({ |
|||
prop: camelCase(o.split(" ")[0]), |
|||
order: (o.split(" ").filter((o) => o)[1] ?? "asc") + "ending", |
|||
})) |
|||
.forEach((o) => sortColumns.value.set(o.prop, o.order)); |
|||
return orderBy; |
|||
}; |
|||
const sortModel = reactive(getSortModel(data)); |
|||
const getClass = ({ row, column }) => { |
|||
if (column.property) { |
|||
column.order = sortColumns.value.get(column.property); |
|||
} |
|||
}; |
|||
const sortChange = ({ column, prop, order }) => { |
|||
if (order === null) { |
|||
sortColumns.value.delete(prop); |
|||
} else { |
|||
sortColumns.value.set(prop, order); |
|||
} |
|||
data.orderBy = Array.from(sortColumns.value) |
|||
.map((o) => capitalize(o[0]) + (o[1] === "ascending" ? "" : ` DESC`)) |
|||
.join(","); |
|||
load(indexUrl); |
|||
}; |
|||
const getColumns = (schema) => { |
|||
Object.keys(schema.properties).forEach((propertyName) => { |
|||
const property = schema.properties[propertyName]; |
|||
if (property.type !== "object" && property.type !== "array" && !property.hidden) { |
|||
columns.value.push({ name: propertyName, title: property.title, checked: true }); |
|||
} |
|||
}); |
|||
}; |
|||
const showColumn = (item, prop) => { |
|||
return ( |
|||
item.type !== "object" && |
|||
item.type !== "array" && |
|||
!item.hidden && |
|||
columns.value.findIndex((o) => o.name === prop && o.checked) >= 0 |
|||
); |
|||
}; |
|||
getColumns(schema.properties.query); |
|||
const queryFromSchema = schema.properties.query; |
|||
const tableSchema = schema.properties.items; |
|||
const editFormRef = ref(null); |
|||
const editFormloading = ref(false); |
|||
const editFormMode = ref(null); |
|||
const editFormTitle = ref(""); |
|||
const editFormSchema = reactive({}); |
|||
const editFormModel = reactive({}); |
|||
const exportModel = reactive({ |
|||
includeAll: false, |
|||
includeDeleted: false, |
|||
}); |
|||
const handleSelectionChange = (rows) => (selectedRows.value = rows); |
|||
const load = async (url) => { |
|||
tableLoading.value = true; |
|||
try { |
|||
const postData = JSON.parse(JSON.stringify(data)); |
|||
delete postData["Id"]; |
|||
delete postData["items"]; |
|||
Object.assign(data, (await post(url, postData)).data); |
|||
} catch (error) { |
|||
console.log(error); |
|||
} finally { |
|||
tableLoading.value = false; |
|||
} |
|||
}; |
|||
const onPageIndexChange = () => load(indexUrl); |
|||
const onPageSizeChange = () => load(indexUrl); |
|||
const click = async (item, rows) => { |
|||
editFormMode.value = item.path; |
|||
context.emit("command", item, rows); |
|||
if (item.path === "index") { |
|||
//list
|
|||
await load(indexUrl); |
|||
} else if (item.path === "details") { |
|||
//details
|
|||
const detailsUrl = `${baseUrl}/${item.path}?${qs.stringify({ id: rows[0].id })}`; |
|||
Object.assign(editFormSchema, schema.properties.items.items); |
|||
Object.assign(editFormModel, (await post(detailsUrl)).data); |
|||
editFormTitle.value = `${t("details")}${schema.title}`; |
|||
dialogVisible.value = true; |
|||
} else if (item.path === "create") { |
|||
//create
|
|||
const url = `${baseUrl}/${item.path}`; |
|||
const vm = (await get(url)).data; |
|||
Object.assign(editFormSchema, vm.schema); |
|||
Object.assign(editFormModel, vm.model); |
|||
editFormTitle.value = `${t("create")}${schema.title}`; |
|||
dialogVisible.value = true; |
|||
} else if (item.path === "update") { |
|||
//update
|
|||
const url = `${baseUrl}/${item.path}`; |
|||
const vm = (await get(url, { id: rows[0].id })).data; |
|||
Object.assign(editFormSchema, vm.schema); |
|||
Object.assign(editFormModel, vm.model); |
|||
editFormTitle.value = `${t("update")}${schema.title}`; |
|||
dialogVisible.value = true; |
|||
} else if (item.path === "delete") { |
|||
//delete
|
|||
if (!rows.length) { |
|||
return; |
|||
} |
|||
const url = `${baseUrl}/${item.path}`; |
|||
await post( |
|||
url, |
|||
rows.map((o) => o.id) |
|||
); |
|||
await load(indexUrl); |
|||
} else if (item.path === "export") { |
|||
//export
|
|||
const url = `${baseUrl}/${item.path}`; |
|||
const exportUrl = `${url}?${qs.stringify(exportModel)}`; |
|||
await load(exportUrl); |
|||
} else if (item.path === "import") { |
|||
//import
|
|||
const url = `${baseUrl}/${item.path}`; |
|||
editFormTitle.value = `${t("import")}${schema.title}`; |
|||
dialogVisible.value = true; |
|||
} |
|||
}; |
|||
const submit = async () => { |
|||
if (editFormMode.value === "create" || editFormMode.value === "update") { |
|||
try { |
|||
const valid = await editFormRef.value.validate(); |
|||
if (valid) { |
|||
editFormloading.value = true; |
|||
const url = `${baseUrl}/${editFormMode.value}`; |
|||
const result = await post(url, editFormModel); |
|||
if (result.errors) { |
|||
model.errors = result.errors; //??
|
|||
} else { |
|||
await load(indexUrl); |
|||
editFormMode.value = null; |
|||
dialogVisible.value = false; |
|||
} |
|||
} |
|||
} catch (error) { |
|||
console.error(error); |
|||
} finally { |
|||
editFormloading.value = false; |
|||
} |
|||
} else if (editFormMode.value === "details") { |
|||
load(indexUrl); |
|||
editFormMode.value = null; |
|||
dialogVisible.value = false; |
|||
} |
|||
}; |
|||
await load(indexUrl); |
|||
return { |
|||
route, |
|||
tableRef, |
|||
tableLoading, |
|||
columns, |
|||
showColumn, |
|||
filterDrawer, |
|||
dialogVisible, |
|||
selectedRows, |
|||
schema, |
|||
queryFromSchema, |
|||
tableSchema, |
|||
data, |
|||
sortModel, |
|||
getClass, |
|||
sortChange, |
|||
getProp, |
|||
editFormRef, |
|||
editFormMode, |
|||
editFormTitle, |
|||
editFormSchema, |
|||
editFormModel, |
|||
exportModel, |
|||
onPageSizeChange, |
|||
onPageIndexChange, |
|||
handleSelectionChange, |
|||
load, |
|||
click, |
|||
submit, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,41 @@ |
|||
import { ref, onMounted } from 'vue'; |
|||
import { marked, setOptions } from '../../lib/marked/marked.esm.js'; |
|||
import mermaid from '../../lib/mermaid/mermaid.esm.min.mjs'; |
|||
import hljs from '../../lib/highlightjs/highlight.min.js'; |
|||
|
|||
export default { |
|||
template: `<div ref="tplRef"><div class="source" style="display:none;"><slot /></div><div class="markdown-body"></div></template>`, |
|||
props: { |
|||
name: { |
|||
default: null |
|||
} |
|||
}, |
|||
setup(props) { |
|||
const tplRef = ref(null); |
|||
mermaid.initialize({ startOnLoad: false }); |
|||
let id = 0; |
|||
onMounted(async () => { |
|||
setOptions({ |
|||
highlight: function (code, lang) { |
|||
if (lang === 'mermaid') { |
|||
return mermaid.mermaidAPI.render(`mermaid${id++}`, code, undefined); |
|||
} else { |
|||
const language = hljs.getLanguage(lang) ? lang : 'plaintext'; |
|||
return hljs.highlight(code, { language }).value; |
|||
} |
|||
}, |
|||
langPrefix: 'hljs language-', |
|||
}); |
|||
let mdText = tplRef.value.querySelector('.source').innerText; |
|||
if (props.name !== null) { |
|||
const response = await fetch(`./assets/docs/${props.name}.md`); |
|||
mdText = await response.text(); |
|||
} |
|||
tplRef.value.querySelector('.markdown-body').innerHTML = marked(mdText); |
|||
tplRef.value.querySelector('.source').remove(); |
|||
}); |
|||
return { |
|||
tplRef |
|||
}; |
|||
} |
|||
} |
@ -0,0 +1,4 @@ |
|||
export default { |
|||
enableLocale: false, |
|||
baseURL: "http://dev.ccwin-in.com:10582/api", |
|||
}; |
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,72 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
|
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
|||
<base href="/" /> |
|||
<style> |
|||
@keyframes loading-rotate { |
|||
to { |
|||
transform: rotate(360deg) |
|||
} |
|||
} |
|||
|
|||
#loading { |
|||
display: none; |
|||
animation: loading-rotate 2s linear infinite; |
|||
} |
|||
|
|||
#loading.loading { |
|||
display: block; |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
margin: auto; |
|||
width: 50px; |
|||
height: 50px; |
|||
} |
|||
</style> |
|||
<link rel="stylesheet" href="./main.css" /> |
|||
<title></title> |
|||
</head> |
|||
|
|||
<body> |
|||
<div id="app"></div> |
|||
<img src="./assets/icons/loading.svg" id="loading" class="loading"> |
|||
<script type="importmap"> |
|||
{ |
|||
"imports": { |
|||
"html":"./utils/index.js", |
|||
"detect-it":"./lib/detect-it/detect-it.esm.js", |
|||
"lodash":"./lib/lodash/lodash.esm.js", |
|||
"vue": "./lib/vue/vue.esm-browser.js", |
|||
"vue-router": "./lib/vue-router/vue-router.esm-browser.js", |
|||
"vue-i18n":"./lib/vue-i18n/vue-i18n.esm-browser.prod.js", |
|||
"pinia": "./lib/pinia/pinia.esm-browser.js", |
|||
"pubsub-js": "./lib/pubsub-js/pubsub.esm.js", |
|||
"linq": "./lib/linq/linq.min.js", |
|||
"@microsoft/signalr": "./lib/@microsoft/signalr/signalr.esm.js", |
|||
"@vueuse/shared": "./lib/@vueuse/shared/index.mjs", |
|||
"@vueuse/core": "./lib/@vueuse/core/index.mjs", |
|||
"element-plus": "./lib/element-plus/index.full.min.mjs", |
|||
"@element-plus/icons-vue":"./lib/@element-plus/icons-vue/index.js", |
|||
"nprogress": "./lib/nprogress/nprogress.vite-esm.js", |
|||
"echarts/core": "./lib/echarts/echarts.esm.min.js", |
|||
"vue-echarts": "./lib/vue-echarts/index.esm.min.js", |
|||
"resize-detector": "./lib/resize-detector/index.js", |
|||
"@vue-office/excel": "./lib/@vue-office/excel/vue-office-excel.mjs", |
|||
"@vue/devtools-api": "./lib/@vue/devtools-api/shim.js", |
|||
"vue-demi": "./lib/vue-demi/shim.js" |
|||
} |
|||
} |
|||
</script> |
|||
<script> |
|||
window.process = { env: { NODE_ENV: 'production' } }; |
|||
</script> |
|||
<script type="module" src="./main.js"></script> |
|||
</body> |
|||
|
|||
</html> |
@ -0,0 +1,12 @@ |
|||
import html from "html"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
|
|||
export default { |
|||
template: html`<div class="footer flex items-center justify-center">{{$t('copyright')}}</div>`, |
|||
setup() { |
|||
const appStore = useAppStore(); |
|||
return { |
|||
appStore, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,168 @@ |
|||
import html from "html"; |
|||
import { ref, onMounted, onUnmounted } from "vue"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import SvgIcon from "../components/icon/index.js"; |
|||
import LayoutLogo from "./logo.js"; |
|||
import { useDark, useFullscreen, useToggle } from "@vueuse/core"; |
|||
import { ElMessage, ElMessageBox } from "element-plus"; |
|||
import { useI18n } from "vue-i18n"; |
|||
import { logout } from "../api/user.js"; |
|||
import LayoutLocale from "./locale.js"; |
|||
import router from "../router/index.js"; |
|||
import { treeToList } from "../utils/index.js"; |
|||
|
|||
export default { |
|||
components: { SvgIcon, LayoutLogo, LayoutLocale, ElMessage, ElMessageBox }, |
|||
template: html` |
|||
<div class="flex items-center justify-between"> |
|||
<div class="flex items-center justify-center"> |
|||
<layout-logo /> |
|||
<el-icon @click="toggleMenuCollapse" class="cursor-pointer"> |
|||
<svg-icon name="unfold" v-if="appStore.isMenuCollapse" /> |
|||
<svg-icon name="fold" v-else /> |
|||
</el-icon> |
|||
</div> |
|||
<div class="flex"> |
|||
<el-space> |
|||
<el-icon class="cursor-pointer" @click="clickSearch"> |
|||
<ep-search /> |
|||
</el-icon> |
|||
<el-select |
|||
ref="searchRef" |
|||
placeholder="search" |
|||
v-show="showSearch" |
|||
@blur="hideSearch" |
|||
filterable |
|||
remote |
|||
:remote-method="searchMenu" |
|||
v-model="searchModel" |
|||
:loading="searchLoading" |
|||
> |
|||
<el-option |
|||
v-for="item in searchOptions" |
|||
:key="item.meta.path" |
|||
:value="item.meta.path" |
|||
:label="item.meta.fullName" |
|||
@click="searchChange(item)" |
|||
/> |
|||
</el-select> |
|||
<el-icon v-model="isDark" @click="toggleDark()" :size="18" class="cursor-pointer"> |
|||
<ep-sunny v-if="isDark" /> |
|||
<ep-moon v-else /> |
|||
</el-icon> |
|||
<el-icon @click="toggleFullscreen" :size="18" class="cursor-pointer"> |
|||
<svg-icon name="fullscreen-exit" v-if="isFullscreen" /> |
|||
<svg-icon name="fullscreen" v-else /> |
|||
</el-icon> |
|||
<el-dropdown class="cursor-pointer" v-if="appStore.token"> |
|||
<span class="el-dropdown-link flex"> |
|||
<el-icon class="el-icon--left" :size="18"> |
|||
<img v-if="appStore.user.avatar" /> |
|||
<ep-user v-else /> |
|||
</el-icon> |
|||
{{ appStore.user.name }} |
|||
<el-icon class="el-icon--right"> |
|||
<ep-arrow-down /> |
|||
</el-icon> |
|||
</span> |
|||
<template #dropdown> |
|||
<el-dropdown-menu> |
|||
<el-dropdown-item> |
|||
<router-link to="/account"> |
|||
<el-icon> <ep-user /> </el-icon>{{$t('userCenter')}} |
|||
</router-link> |
|||
</el-dropdown-item> |
|||
<el-dropdown-item divided @click="confirmLogout"> |
|||
<el-icon> <ep-switch-button /> </el-icon>{{$t('logout')}} |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</template> |
|||
</el-dropdown> |
|||
<el-link type="info" v-else> |
|||
<router-link to="/register"> {{$t('register')}}</router-link> |
|||
</el-link> |
|||
<layout-locale /> |
|||
</el-space> |
|||
</div> |
|||
</div> |
|||
`,
|
|||
setup() { |
|||
const i18n = useI18n(); |
|||
const appStore = useAppStore(); |
|||
//
|
|||
const searchRef = ref(null); |
|||
const searchLoading = ref(false); |
|||
const searchModel = ref(""); |
|||
const searchOptions = ref([]); |
|||
const showSearch = ref(false); |
|||
const hideSearch = () => { |
|||
showSearch.value = false; |
|||
}; |
|||
const clickSearch = () => { |
|||
showSearch.value = !showSearch.value; |
|||
if (showSearch.value) { |
|||
searchRef.value.focus(); |
|||
} |
|||
}; |
|||
const searchMenu = (query) => { |
|||
if (query) { |
|||
try { |
|||
searchLoading.value = true; |
|||
const menus = treeToList(router.getRoutes().find((o) => o.path === "/").children); |
|||
searchOptions.value = menus |
|||
.filter((o) => !o.children || o.children.length === 0) |
|||
.filter((o) => o.meta.fullName.indexOf(query) > -1); |
|||
} finally { |
|||
searchLoading.value = false; |
|||
} |
|||
} |
|||
}; |
|||
const searchChange = (route) => { |
|||
if (!route.meta.isExternal) { |
|||
router.push(route.meta.path); |
|||
searchModel.value = ""; |
|||
searchOptions.value = []; |
|||
showSearch.value = false; |
|||
} else { |
|||
window.open(route.path); |
|||
} |
|||
}; |
|||
//
|
|||
const isDark = useDark(); |
|||
const toggleDark = useToggle(isDark); |
|||
const toggleMenuCollapse = () => (appStore.isMenuCollapse = !appStore.isMenuCollapse); |
|||
//
|
|||
const { isFullscreen, toggle: toggleFullscreen } = useFullscreen(document.documentElement); |
|||
const confirmLogout = async () => { |
|||
try { |
|||
await ElMessageBox.confirm(i18n.t("confirmLogout"), i18n.t("tip"), { type: "warning" }); |
|||
logout(); |
|||
} catch (error) { |
|||
if (error === "cancel") { |
|||
ElMessage({ |
|||
type: "info", |
|||
message: i18n.t("cancel"), |
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
return { |
|||
appStore, |
|||
showSearch, |
|||
hideSearch, |
|||
clickSearch, |
|||
searchRef, |
|||
searchLoading, |
|||
searchModel, |
|||
searchOptions, |
|||
searchMenu, |
|||
searchChange, |
|||
isDark, |
|||
toggleDark, |
|||
toggleMenuCollapse, |
|||
isFullscreen, |
|||
toggleFullscreen, |
|||
confirmLogout, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,57 @@ |
|||
import html from "html"; |
|||
import LayoutHeader from "./header.js"; |
|||
import LayoutMenu from "./menu.js"; |
|||
import LayoutTabs from "./tabs.js"; |
|||
import LayoutFooter from "./footer.js"; |
|||
import Icon from "../components/icon/index.js"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import { computed } from "vue"; |
|||
|
|||
export default { |
|||
components: { Icon, LayoutHeader, LayoutMenu, LayoutTabs, LayoutFooter }, |
|||
template: html`<el-container>
|
|||
<el-header><layout-header /></el-header> |
|||
<el-container> |
|||
<el-aside width="auto"> |
|||
<el-scrollbar><layout-menu /></el-scrollbar> |
|||
</el-aside> |
|||
<el-container class="backtop"> |
|||
<el-scrollbar> |
|||
<layout-tabs /> |
|||
<el-main> |
|||
<router-view v-if="!isRefreshing" v-slot="{ Component, route }"> |
|||
<component |
|||
:is="Component" |
|||
v-if="!appStore.isUseTabsRouter || !route.meta?.cached" |
|||
:key="$route.fullPath" |
|||
/> |
|||
<keep-alive> |
|||
<component |
|||
:is="Component" |
|||
v-if="appStore.isUseTabsRouter && route.meta?.cached" |
|||
:key="route.fullPath" |
|||
/> |
|||
</keep-alive> |
|||
</router-view> |
|||
</el-main> |
|||
<el-footer> |
|||
<layout-footer /> |
|||
</el-footer> |
|||
<el-backtop target=".backtop > .el-scrollbar > .el-scrollbar__wrap" /> |
|||
</el-scrollbar> |
|||
</el-container> |
|||
</el-container> |
|||
</el-container>`, |
|||
setup() { |
|||
const appStore = useAppStore(); |
|||
const isRefreshing = computed(() => appStore.isRefreshing); |
|||
const path = computed(() => useRoute().matched[0].path); |
|||
const items = computed(() => useRoute().matched[0].children); |
|||
return { |
|||
appStore, |
|||
isRefreshing, |
|||
path, |
|||
items, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,36 @@ |
|||
import html from "html"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import { useI18n } from "vue-i18n"; |
|||
import Icon from "../components/icon/index.js"; |
|||
export default { |
|||
components: { Icon }, |
|||
template: html`<el-dropdown class="cursor-pointer" v-if="appStore.settings.enableLocale">
|
|||
<span class="el-dropdown-link flex"> |
|||
<el-icon :size="18"> |
|||
<icon name="lang" /> |
|||
</el-icon> |
|||
</span> |
|||
<template #dropdown> |
|||
<el-dropdown-menu> |
|||
<el-dropdown-item v-for="locale in $i18n.availableLocales" @click="changeLocale(locale)"> |
|||
{{appStore.localization.options.find(o=>o.value===locale).label}} |
|||
<el-icon class="el-icon--right" v-if="locale===$i18n.locale"> |
|||
<ep-select /> |
|||
</el-icon> |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</template> |
|||
</el-dropdown>`, |
|||
setup() { |
|||
const appStore = useAppStore(); |
|||
const i18n = useI18n(); |
|||
const changeLocale = (locale) => { |
|||
appStore.localization.locale = locale; |
|||
i18n.locale.value = locale; |
|||
}; |
|||
return { |
|||
appStore, |
|||
changeLocale, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,17 @@ |
|||
import html from "html"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
|
|||
export default { |
|||
template: html`<router-link to="/" class="logo">
|
|||
<div class="flex h-full items-center"> |
|||
<img src="/assets/logo.svg" /> |
|||
<h1 v-if="!appStore.isMenuCollapse">{{$t('application')}}</h1> |
|||
</div> |
|||
</router-link>`, |
|||
setup() { |
|||
const appStore = useAppStore(); |
|||
return { |
|||
appStore, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,55 @@ |
|||
import html from "html"; |
|||
import { reactive, watch } from "vue"; |
|||
import Icon from "../components/icon/index.js"; |
|||
import { useRouter } from "vue-router"; |
|||
|
|||
export default { |
|||
name: "menuItem", |
|||
components: { Icon }, |
|||
template: html`<el-sub-menu :index="modelValue.meta.path" v-if="modelValue.children">
|
|||
<template #title> |
|||
<el-icon><icon :name="modelValue.meta.icon??'folder'" /></el-icon> |
|||
<span>{{modelValue.meta.title}}</span> |
|||
</template> |
|||
<menu-item v-for="item in modelValue.children" v-model="item" /> |
|||
</el-sub-menu> |
|||
<el-menu-item |
|||
v-else |
|||
:index="modelValue.meta.isExternal?null:modelValue.meta.path" |
|||
@click.native="click(modelValue)" |
|||
> |
|||
<el-icon><icon :name="modelValue.meta.icon??file" /></el-icon> |
|||
<template #title> |
|||
<span>{{modelValue.meta.title}}</span> |
|||
</template> |
|||
</el-menu-item>`, |
|||
props: { |
|||
modelValue: { |
|||
typeof: Object, |
|||
}, |
|||
}, |
|||
setup(props, context) { |
|||
const router = useRouter(); |
|||
const model = reactive(props.modelValue); |
|||
watch( |
|||
model, |
|||
(value) => { |
|||
context.emit("update:modelValue", value); |
|||
}, |
|||
{ deep: true } |
|||
); |
|||
//
|
|||
const click = (route) => { |
|||
if (!route.meta.isExternal) { |
|||
router.push(route.meta.path); |
|||
} else { |
|||
window.open(route.path); |
|||
} |
|||
}; |
|||
//
|
|||
return { |
|||
model, |
|||
click, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,24 @@ |
|||
import html from "html"; |
|||
import Icon from "../components/icon/index.js"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import MenuItem from "./menu-item.js"; |
|||
import router from "../router/index.js"; |
|||
|
|||
export default { |
|||
components: { Icon, MenuItem }, |
|||
template: html`<el-menu
|
|||
:collapse="appStore.isMenuCollapse" |
|||
:collapse-transition="false" |
|||
:default-active="$route.fullPath" |
|||
> |
|||
<menu-item v-for="item in menus" v-model="item" /> |
|||
</el-menu>`, |
|||
setup() { |
|||
const appStore = useAppStore(); |
|||
const menus = router.getRoutes().find((o) => o.name === "layout").children; |
|||
return { |
|||
appStore, |
|||
menus, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,171 @@ |
|||
import html from "html"; |
|||
import { ref, nextTick } from "vue"; |
|||
import { useRoute, onBeforeRouteUpdate, useRouter } from "vue-router"; |
|||
import Icon from "../components/icon/index.js"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import MenuItem from "./menu-item.js"; |
|||
|
|||
export default { |
|||
components: { Icon, MenuItem }, |
|||
template: html`<el-tabs
|
|||
v-model="model" |
|||
type="border-card" |
|||
class="router-tab" |
|||
@tab-remove="remove" |
|||
@tab-click="onClick" |
|||
> |
|||
<template v-for="(item, index) in appStore.routes" :key="item.fullPath"> |
|||
<el-tab-pane v-model="item.fullPath" :name="item.fullPath" :closable="appStore.routes.length > 1"> |
|||
<template #label> |
|||
<el-dropdown |
|||
:ref="(el) => setRef(index, el)" |
|||
class="h-full" |
|||
trigger="contextmenu" |
|||
@visible-change="showContextMenu(index, $event)" |
|||
> |
|||
<span class="inline-flex items-center"> |
|||
<el-icon><icon v-if="item.meta.icon" :name="item.meta.icon" /></el-icon> |
|||
{{ item.meta?.title ?? item.fullPath }} |
|||
</span> |
|||
<template #dropdown> |
|||
<el-dropdown-menu> |
|||
<el-dropdown-item @click="refresh(index)"><i-ep-refresh />刷新</el-dropdown-item> |
|||
<el-dropdown-item :disabled="index === 0" @click="removeLeft(index)"> |
|||
<i-ep-back />关闭左侧 |
|||
</el-dropdown-item> |
|||
<el-dropdown-item :disabled="index === appStore.routes.length - 1" @click="removeRight(index)"> |
|||
<i-ep-right />关闭右侧 |
|||
</el-dropdown-item> |
|||
<el-dropdown-item |
|||
:disabled="index === 0 && index === appStore.routes.length - 1" |
|||
@click="removeOthers(index)" |
|||
> |
|||
<i-ep-switch />关闭其他 |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</template> |
|||
</el-dropdown> |
|||
</template> |
|||
</el-tab-pane> |
|||
</template> |
|||
</el-tabs>`, |
|||
styles: html` |
|||
<style> |
|||
.router-tab { |
|||
box-sizing: border-box; |
|||
height: 40px !important; |
|||
background-color: var(--el-fill-color-blank); |
|||
border-width: 0 !important; |
|||
} |
|||
|
|||
.router-tab .el-tabs__item { |
|||
padding: 13px !important; |
|||
border-bottom-width: 0; |
|||
} |
|||
|
|||
.router-tab .el-tabs__content { |
|||
display: none; |
|||
} |
|||
</style> |
|||
`,
|
|||
setup() { |
|||
const appStore = useAppStore(); |
|||
const itemRefs = ref([]); |
|||
const currentRoute = useRoute(); |
|||
const router = useRouter(); |
|||
const model = ref(currentRoute.fullPath); |
|||
|
|||
onBeforeRouteUpdate((to) => { |
|||
model.value = to.fullPath; |
|||
}); |
|||
|
|||
const setRef = (index, el) => { |
|||
if (el) { |
|||
itemRefs.value[index] = el; |
|||
} else { |
|||
itemRefs.value.splice(index, 1); |
|||
} |
|||
}; |
|||
const showContextMenu = (index, show) => { |
|||
if (show) { |
|||
itemRefs.value.forEach((item, i) => { |
|||
if (i !== index) { |
|||
item?.handleClose(); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
const refresh = (index) => { |
|||
const currentIndex = appStore.routes.findIndex((o) => o.fullPath === currentRoute.fullPath); |
|||
const route = appStore.routes[index]; |
|||
if (index !== currentIndex) { |
|||
router.push({ path: route.fullPath }); |
|||
} |
|||
appStore.isRefreshing = true; |
|||
nextTick(() => { |
|||
appStore.isRefreshing = false; |
|||
}); |
|||
}; |
|||
|
|||
const remove = (name) => { |
|||
if (appStore.routes.length > 1) { |
|||
const index = appStore.routes.findIndex((o) => o.fullPath === name); |
|||
const currentIndex = appStore.routes.findIndex((o) => o.fullPath === currentRoute.fullPath); |
|||
appStore.routes.splice(index, 1); |
|||
if (index === currentIndex) { |
|||
if (appStore.routes[index]) { |
|||
router.push(appStore.routes[index]); |
|||
} else { |
|||
router.push(appStore.routes[index - 1]); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
const removeLeft = (index) => { |
|||
const currentIndex = appStore.routes.findIndex((o) => o.fullPath === currentRoute.fullPath); |
|||
const route = appStore.routes[index]; |
|||
appStore.routes.splice(0, index); |
|||
if (currentIndex < index) { |
|||
router.push(route); |
|||
} |
|||
}; |
|||
|
|||
const removeRight = (index) => { |
|||
const currentIndex = appStore.routes.findIndex((o) => o.fullPath === currentRoute.fullPath); |
|||
appStore.routes.splice(index + 1, appStore.routes.length - index); |
|||
if (currentIndex > index) { |
|||
router.push(appStore.routes[index]); |
|||
} |
|||
}; |
|||
|
|||
const removeOthers = (index) => { |
|||
removeRight(index); |
|||
removeLeft(index); |
|||
if (appStore.routes[0].fullPath !== currentRoute.fullPath) { |
|||
router.push(appStore.routes[0]); |
|||
} |
|||
}; |
|||
|
|||
const onClick = (context) => { |
|||
if (!context.active) { |
|||
router.push(context.props.name); |
|||
} |
|||
}; |
|||
return { |
|||
model, |
|||
appStore, |
|||
itemRefs, |
|||
onBeforeRouteUpdate, |
|||
setRef, |
|||
showContextMenu, |
|||
refresh, |
|||
remove, |
|||
removeLeft, |
|||
removeRight, |
|||
removeOthers, |
|||
onClick, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,765 @@ |
|||
body { |
|||
margin: 0; |
|||
} |
|||
.x-spreadsheet { |
|||
font-size: 13px; |
|||
line-height: normal; |
|||
user-select: none; |
|||
-moz-user-select: none; |
|||
font-family: 'Lato', 'Source Sans Pro', Roboto, Helvetica, Arial, sans-serif; |
|||
box-sizing: content-box; |
|||
background: #fff; |
|||
-webkit-font-smoothing: antialiased; |
|||
} |
|||
.x-spreadsheet textarea { |
|||
font: 400 13px Arial, 'Lato', 'Source Sans Pro', Roboto, Helvetica, sans-serif; |
|||
} |
|||
.x-spreadsheet-sheet { |
|||
position: relative; |
|||
overflow: hidden; |
|||
} |
|||
.x-spreadsheet-table { |
|||
vertical-align: bottom; |
|||
} |
|||
.x-spreadsheet-tooltip { |
|||
font-family: inherit; |
|||
position: absolute; |
|||
padding: 5px 10px; |
|||
color: #fff; |
|||
border-radius: 1px; |
|||
background: #000000; |
|||
font-size: 12px; |
|||
z-index: 201; |
|||
} |
|||
.x-spreadsheet-tooltip:before { |
|||
pointer-events: none; |
|||
position: absolute; |
|||
left: calc(50% - 4px); |
|||
top: -4px; |
|||
content: ""; |
|||
width: 8px; |
|||
height: 8px; |
|||
background: inherit; |
|||
-webkit-transform: rotate(45deg); |
|||
transform: rotate(45deg); |
|||
z-index: 1; |
|||
box-shadow: 1px 1px 3px -1px rgba(0, 0, 0, 0.3); |
|||
} |
|||
.x-spreadsheet-color-palette { |
|||
padding: 5px; |
|||
} |
|||
.x-spreadsheet-color-palette table { |
|||
margin: 0; |
|||
padding: 0; |
|||
border-collapse: separate; |
|||
border-spacing: 2; |
|||
background: #fff; |
|||
} |
|||
.x-spreadsheet-color-palette table td { |
|||
margin: 0; |
|||
cursor: pointer; |
|||
border: 1px solid transparent; |
|||
} |
|||
.x-spreadsheet-color-palette table td:hover { |
|||
border-color: #ddd; |
|||
} |
|||
.x-spreadsheet-color-palette table td .x-spreadsheet-color-palette-cell { |
|||
width: 16px; |
|||
height: 16px; |
|||
} |
|||
.x-spreadsheet-border-palette { |
|||
padding: 6px; |
|||
} |
|||
.x-spreadsheet-border-palette table { |
|||
margin: 0; |
|||
padding: 0; |
|||
border-collapse: separate; |
|||
border-spacing: 0; |
|||
background: #fff; |
|||
table-layout: fixed; |
|||
} |
|||
.x-spreadsheet-border-palette table td { |
|||
margin: 0; |
|||
} |
|||
.x-spreadsheet-border-palette .x-spreadsheet-border-palette-left { |
|||
border-right: 1px solid #eee; |
|||
padding-right: 6px; |
|||
} |
|||
.x-spreadsheet-border-palette .x-spreadsheet-border-palette-left .x-spreadsheet-border-palette-cell { |
|||
width: 30px; |
|||
height: 30px; |
|||
cursor: pointer; |
|||
text-align: center; |
|||
} |
|||
.x-spreadsheet-border-palette .x-spreadsheet-border-palette-left .x-spreadsheet-border-palette-cell:hover { |
|||
background-color: #eee; |
|||
} |
|||
.x-spreadsheet-border-palette .x-spreadsheet-border-palette-right { |
|||
padding-left: 6px; |
|||
} |
|||
.x-spreadsheet-border-palette .x-spreadsheet-border-palette-right .x-spreadsheet-line-type { |
|||
position: relative; |
|||
left: 0; |
|||
top: -3px; |
|||
} |
|||
.x-spreadsheet-dropdown { |
|||
position: relative; |
|||
} |
|||
.x-spreadsheet-dropdown .x-spreadsheet-dropdown-content { |
|||
position: absolute; |
|||
z-index: 200; |
|||
background: #fff; |
|||
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15); |
|||
} |
|||
.x-spreadsheet-dropdown.bottom-left .x-spreadsheet-dropdown-content { |
|||
top: calc(100% + 5px); |
|||
left: 0; |
|||
} |
|||
.x-spreadsheet-dropdown.bottom-right .x-spreadsheet-dropdown-content { |
|||
top: calc(100% + 5px); |
|||
right: 0; |
|||
} |
|||
.x-spreadsheet-dropdown.top-left .x-spreadsheet-dropdown-content { |
|||
bottom: calc(100% + 5px); |
|||
left: 0; |
|||
} |
|||
.x-spreadsheet-dropdown.top-right .x-spreadsheet-dropdown-content { |
|||
bottom: calc(100% + 5px); |
|||
right: 0; |
|||
} |
|||
.x-spreadsheet-dropdown .x-spreadsheet-dropdown-title { |
|||
padding: 0 5px; |
|||
display: inline-block; |
|||
} |
|||
/* resizer **/ |
|||
.x-spreadsheet-resizer { |
|||
position: absolute; |
|||
z-index: 11; |
|||
} |
|||
.x-spreadsheet-resizer .x-spreadsheet-resizer-hover { |
|||
background-color: rgba(75, 137, 255, 0.25); |
|||
} |
|||
.x-spreadsheet-resizer .x-spreadsheet-resizer-line { |
|||
position: absolute; |
|||
} |
|||
.x-spreadsheet-resizer.horizontal { |
|||
cursor: row-resize; |
|||
} |
|||
.x-spreadsheet-resizer.horizontal .x-spreadsheet-resizer-line { |
|||
border-bottom: 2px dashed #4b89ff; |
|||
left: 0; |
|||
bottom: 0; |
|||
} |
|||
.x-spreadsheet-resizer.vertical { |
|||
cursor: col-resize; |
|||
} |
|||
.x-spreadsheet-resizer.vertical .x-spreadsheet-resizer-line { |
|||
border-right: 2px dashed #4b89ff; |
|||
top: 0; |
|||
right: 0; |
|||
} |
|||
/* scrollbar */ |
|||
.x-spreadsheet-scrollbar { |
|||
position: absolute; |
|||
bottom: 0; |
|||
right: 0; |
|||
background-color: #f4f5f8; |
|||
opacity: 0.9; |
|||
z-index: 12; |
|||
} |
|||
.x-spreadsheet-scrollbar.horizontal { |
|||
right: 15px; |
|||
overflow-x: scroll; |
|||
overflow-y: hidden; |
|||
} |
|||
.x-spreadsheet-scrollbar.horizontal > div { |
|||
height: 1px; |
|||
background: #ddd; |
|||
} |
|||
.x-spreadsheet-scrollbar.vertical { |
|||
bottom: 15px; |
|||
overflow-x: hidden; |
|||
overflow-y: scroll; |
|||
} |
|||
.x-spreadsheet-scrollbar.vertical > div { |
|||
width: 1px; |
|||
background: #ddd; |
|||
} |
|||
/* @{css-prefix}-overlayer */ |
|||
.x-spreadsheet-overlayer { |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
z-index: 10; |
|||
} |
|||
.x-spreadsheet-overlayer .x-spreadsheet-overlayer-content { |
|||
position: absolute; |
|||
overflow: hidden; |
|||
pointer-events: none; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
.x-spreadsheet-editor, |
|||
.x-spreadsheet-selector { |
|||
box-sizing: content-box; |
|||
position: absolute; |
|||
overflow: hidden; |
|||
pointer-events: none; |
|||
top: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
/* @{css-prefix}-selector */ |
|||
.x-spreadsheet-selector .hide-input { |
|||
position: absolute; |
|||
z-index: 0; |
|||
} |
|||
.x-spreadsheet-selector .hide-input input { |
|||
padding: 0; |
|||
width: 0; |
|||
border: none!important; |
|||
} |
|||
.x-spreadsheet-selector .x-spreadsheet-selector-area { |
|||
position: absolute; |
|||
border: 2px solid #4b89ff; |
|||
background: rgba(75, 137, 255, 0.1); |
|||
z-index: 5; |
|||
} |
|||
.x-spreadsheet-selector .x-spreadsheet-selector-clipboard, |
|||
.x-spreadsheet-selector .x-spreadsheet-selector-autofill { |
|||
position: absolute; |
|||
background: transparent; |
|||
z-index: 100; |
|||
} |
|||
.x-spreadsheet-selector .x-spreadsheet-selector-clipboard { |
|||
border: 2px dashed #4b89ff; |
|||
} |
|||
.x-spreadsheet-selector .x-spreadsheet-selector-autofill { |
|||
border: 1px dashed rgba(0, 0, 0, 0.45); |
|||
} |
|||
.x-spreadsheet-selector .x-spreadsheet-selector-corner { |
|||
pointer-events: auto; |
|||
position: absolute; |
|||
cursor: crosshair; |
|||
font-size: 0; |
|||
height: 5px; |
|||
width: 5px; |
|||
right: -5px; |
|||
bottom: -5px; |
|||
border: 2px solid #ffffff; |
|||
background: #4b89ff; |
|||
} |
|||
.x-spreadsheet-editor { |
|||
z-index: 20; |
|||
} |
|||
.x-spreadsheet-editor .x-spreadsheet-editor-area { |
|||
position: absolute; |
|||
text-align: left; |
|||
border: 2px solid #4b89ff; |
|||
line-height: 0; |
|||
z-index: 100; |
|||
pointer-events: auto; |
|||
} |
|||
.x-spreadsheet-editor .x-spreadsheet-editor-area textarea { |
|||
box-sizing: content-box; |
|||
border: none; |
|||
padding: 0 3px; |
|||
outline: none; |
|||
resize: none; |
|||
text-align: start; |
|||
overflow-y: hidden; |
|||
font: 400 13px Arial, 'Lato', 'Source Sans Pro', Roboto, Helvetica, sans-serif; |
|||
color: inherit; |
|||
white-space: normal; |
|||
word-wrap: break-word; |
|||
line-height: 22px; |
|||
margin: 0; |
|||
} |
|||
.x-spreadsheet-editor .x-spreadsheet-editor-area .textline { |
|||
overflow: hidden; |
|||
visibility: hidden; |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
} |
|||
.x-spreadsheet-item { |
|||
user-select: none; |
|||
background: 0; |
|||
border: 1px solid transparent; |
|||
outline: none; |
|||
height: 26px; |
|||
color: rgba(0, 0, 0, 0.9); |
|||
line-height: 26px; |
|||
list-style: none; |
|||
padding: 2px 10px; |
|||
cursor: default; |
|||
text-align: left; |
|||
overflow: hidden; |
|||
} |
|||
.x-spreadsheet-item.disabled { |
|||
pointer-events: none; |
|||
opacity: 0.5; |
|||
} |
|||
.x-spreadsheet-item:hover, |
|||
.x-spreadsheet-item.active { |
|||
background: rgba(0, 0, 0, 0.05); |
|||
} |
|||
.x-spreadsheet-item.divider { |
|||
height: 0; |
|||
padding: 0; |
|||
margin: 5px 0; |
|||
border: none; |
|||
border-bottom: 1px solid rgba(0, 0, 0, 0.1); |
|||
} |
|||
.x-spreadsheet-item .label { |
|||
float: right; |
|||
opacity: 0.65; |
|||
font-size: 1em; |
|||
} |
|||
.x-spreadsheet-item.state, |
|||
.x-spreadsheet-header.state { |
|||
padding-left: 35px!important; |
|||
position: relative; |
|||
} |
|||
.x-spreadsheet-item.state:before, |
|||
.x-spreadsheet-header.state:before { |
|||
content: ''; |
|||
position: absolute; |
|||
width: 10px; |
|||
height: 10px; |
|||
left: 12px; |
|||
top: calc(50% - 5px); |
|||
background: rgba(0, 0, 0, 0.08); |
|||
border-radius: 2px; |
|||
} |
|||
.x-spreadsheet-item.state.checked:before, |
|||
.x-spreadsheet-header.state.checked:before { |
|||
background: #4b89ff; |
|||
} |
|||
.x-spreadsheet-checkbox { |
|||
position: relative; |
|||
display: inline-block; |
|||
backface-visibility: hidden; |
|||
outline: 0; |
|||
vertical-align: baseline; |
|||
font-style: normal; |
|||
font-size: 1rem; |
|||
line-height: 1em; |
|||
} |
|||
.x-spreadsheet-checkbox > input { |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
opacity: 0!important; |
|||
outline: 0; |
|||
z-index: -1; |
|||
} |
|||
.x-spreadsheet-suggest, |
|||
.x-spreadsheet-contextmenu, |
|||
.x-spreadsheet-sort-filter { |
|||
position: absolute; |
|||
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15); |
|||
background: #fff; |
|||
z-index: 100; |
|||
width: 260px; |
|||
pointer-events: auto; |
|||
overflow: auto; |
|||
} |
|||
.x-spreadsheet-suggest { |
|||
width: 200px; |
|||
} |
|||
.x-spreadsheet-filter { |
|||
border: 1px solid #e9e9e9; |
|||
font-size: 12px; |
|||
margin: 10px; |
|||
} |
|||
.x-spreadsheet-filter .x-spreadsheet-header { |
|||
padding: 0.5em 0.75em; |
|||
background: #f8f8f9; |
|||
border-bottom: 1px solid #e9e9e9; |
|||
border-left: 1px solid transparent; |
|||
} |
|||
.x-spreadsheet-filter .x-spreadsheet-body { |
|||
height: 200px; |
|||
overflow-y: auto; |
|||
} |
|||
.x-spreadsheet-filter .x-spreadsheet-body .x-spreadsheet-item { |
|||
height: 20px; |
|||
line-height: 20px; |
|||
} |
|||
.x-spreadsheet-sort-filter .x-spreadsheet-buttons { |
|||
margin: 10px; |
|||
} |
|||
.x-spreadsheet-bottombar { |
|||
height: 40px; |
|||
padding: 0 30px; |
|||
text-align: left; |
|||
background: #f5f6f7; |
|||
display: flex; |
|||
} |
|||
.x-spreadsheet-bottombar { |
|||
position: relative; |
|||
border-top: 1px solid #e0e2e4; |
|||
} |
|||
.x-spreadsheet-bottombar .x-spreadsheet-menu > li { |
|||
line-height: 40px; |
|||
height: 40px; |
|||
padding-top: 0; |
|||
padding-bottom: 0; |
|||
vertical-align: middle; |
|||
border-right: 1px solid #e8eaed; |
|||
} |
|||
.x-spreadsheet-menu { |
|||
list-style: none; |
|||
margin: 0; |
|||
padding: 0; |
|||
user-select: none; |
|||
} |
|||
.x-spreadsheet-menu > li { |
|||
float: left; |
|||
line-height: 1.25em; |
|||
padding: 0.785em 1em; |
|||
margin: 0; |
|||
vertical-align: middle; |
|||
text-align: left; |
|||
font-weight: 400; |
|||
color: #80868b; |
|||
white-space: nowrap; |
|||
cursor: pointer; |
|||
transition: all 0.3s; |
|||
font-weight: bold; |
|||
} |
|||
.x-spreadsheet-menu > li.active { |
|||
background-color: #fff; |
|||
color: rgba(0, 0, 0, 0.65); |
|||
} |
|||
.x-spreadsheet-menu > li .x-spreadsheet-dropdown { |
|||
display: inline-block; |
|||
} |
|||
.x-spreadsheet-print { |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
z-index: 100; |
|||
width: 100%; |
|||
height: 100%; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
.x-spreadsheet-print-bar { |
|||
background: #424242; |
|||
height: 60px; |
|||
line-height: 60px; |
|||
padding: 0 30px; |
|||
} |
|||
.x-spreadsheet-print-bar .-title { |
|||
color: #fff; |
|||
font-weight: bold; |
|||
font-size: 1.2em; |
|||
float: left; |
|||
} |
|||
.x-spreadsheet-print-bar .-right { |
|||
float: right; |
|||
margin-top: 12px; |
|||
} |
|||
.x-spreadsheet-print-content { |
|||
display: flex; |
|||
flex: auto; |
|||
flex-direction: row; |
|||
background: #d0d0d0; |
|||
height: calc(100% - 60px); |
|||
} |
|||
.x-spreadsheet-print-content .-sider { |
|||
flex: 0 0 300px; |
|||
width: 300px; |
|||
border-left: 2px solid #ccc; |
|||
background: #fff; |
|||
} |
|||
.x-spreadsheet-print-content .-content { |
|||
flex: auto; |
|||
overflow-x: auto; |
|||
overflow-y: scroll; |
|||
height: 100%; |
|||
} |
|||
.x-spreadsheet-canvas-card-wraper { |
|||
margin: 40px 20px; |
|||
} |
|||
.x-spreadsheet-canvas-card { |
|||
background: #fff; |
|||
margin: auto; |
|||
page-break-before: auto; |
|||
page-break-after: always; |
|||
box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 3px rgba(0, 0, 0, 0.12), 0 4px 5px 0 rgba(0, 0, 0, 0.2); |
|||
} |
|||
.x-spreadsheet-calendar { |
|||
color: rgba(0, 0, 0, 0.65); |
|||
background: #ffffff; |
|||
user-select: none; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-header { |
|||
font-weight: 700; |
|||
line-height: 30px; |
|||
text-align: center; |
|||
width: 100%; |
|||
float: left; |
|||
background: #f9fafb; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-header .calendar-header-left { |
|||
padding-left: 5px; |
|||
float: left; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-header .calendar-header-right { |
|||
float: right; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-header .calendar-header-right a { |
|||
padding: 3px 0; |
|||
margin-right: 2px; |
|||
border-radius: 2px; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-header .calendar-header-right a:hover { |
|||
background: rgba(0, 0, 0, 0.08); |
|||
} |
|||
.x-spreadsheet-calendar .calendar-body { |
|||
border-collapse: collapse; |
|||
border-spacing: 0; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-body th, |
|||
.x-spreadsheet-calendar .calendar-body td { |
|||
width: 14.28571429%; |
|||
min-width: 32px; |
|||
text-align: center; |
|||
font-weight: 700; |
|||
line-height: 30px; |
|||
padding: 0; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-body td > .cell:hover { |
|||
background: #ecf6fd; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-body td > .cell.active, |
|||
.x-spreadsheet-calendar .calendar-body td > .cell.active:hover { |
|||
background: #ecf6fd; |
|||
color: #2185D0; |
|||
} |
|||
.x-spreadsheet-calendar .calendar-body td > .cell.disabled { |
|||
pointer-events: none; |
|||
opacity: 0.5; |
|||
} |
|||
.x-spreadsheet-datepicker { |
|||
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); |
|||
position: absolute; |
|||
left: 0; |
|||
top: calc(100% + 5px); |
|||
z-index: 10; |
|||
width: auto; |
|||
} |
|||
.x-spreadsheet-buttons { |
|||
display: flex; |
|||
justify-content: flex-end; |
|||
} |
|||
.x-spreadsheet-buttons .x-spreadsheet-button { |
|||
margin-left: 8px; |
|||
} |
|||
.x-spreadsheet-button { |
|||
display: inline-block; |
|||
border-radius: 3px; |
|||
line-height: 1em; |
|||
min-height: 1em; |
|||
white-space: nowrap; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
font-size: 1em; |
|||
font-weight: 700; |
|||
padding: 0.75em 1em; |
|||
color: rgba(0, 0, 0, 0.6); |
|||
background: #E0E1E2; |
|||
text-decoration: none; |
|||
font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; |
|||
outline: none; |
|||
vertical-align: baseline; |
|||
zoom: 1; |
|||
user-select: none; |
|||
transition: all 0.1s linear; |
|||
} |
|||
.x-spreadsheet-button.active, |
|||
.x-spreadsheet-button:hover { |
|||
background-color: #C0C1C2; |
|||
color: rgba(0, 0, 0, 0.8); |
|||
} |
|||
.x-spreadsheet-button.primary { |
|||
color: #fff; |
|||
background-color: #2185D0; |
|||
} |
|||
.x-spreadsheet-button.primary:hover, |
|||
.x-spreadsheet-button.primary.active { |
|||
color: #fff; |
|||
background-color: #1678c2; |
|||
} |
|||
.x-spreadsheet-form-input { |
|||
font-size: 1em; |
|||
position: relative; |
|||
font-weight: 400; |
|||
display: inline-flex; |
|||
color: rgba(0, 0, 0, 0.87); |
|||
} |
|||
.x-spreadsheet-form-input input { |
|||
z-index: 1; |
|||
margin: 0; |
|||
max-width: 100%; |
|||
flex: 1 0 auto; |
|||
outline: 0; |
|||
-webkit-tap-highlight-color: rgba(255, 255, 255, 0); |
|||
text-align: left; |
|||
line-height: 30px; |
|||
height: 30px; |
|||
padding: 0 8px; |
|||
background: #fff; |
|||
border: 1px solid #e9e9e9; |
|||
border-radius: 3px; |
|||
transition: box-shadow 0.1s ease, border-color 0.1s ease; |
|||
box-shadow: inset 0 1px 2px hsla(0, 0%, 4%, 0.06); |
|||
} |
|||
.x-spreadsheet-form-input input:focus { |
|||
border-color: #4b89ff; |
|||
box-shadow: inset 0 1px 2px rgba(75, 137, 255, 0.2); |
|||
} |
|||
.x-spreadsheet-form-select { |
|||
position: relative; |
|||
display: inline-block; |
|||
background: #fff; |
|||
border: 1px solid #e9e9e9; |
|||
border-radius: 2px; |
|||
cursor: pointer; |
|||
color: rgba(0, 0, 0, 0.87); |
|||
user-select: none; |
|||
box-shadow: inset 0 1px 2px hsla(0, 0%, 4%, 0.06); |
|||
} |
|||
.x-spreadsheet-form-select .input-text { |
|||
text-overflow: ellipsis; |
|||
white-space: nowrap; |
|||
min-width: 60px; |
|||
width: auto; |
|||
height: 30px; |
|||
line-height: 30px; |
|||
padding: 0 8px; |
|||
} |
|||
.x-spreadsheet-form-fields { |
|||
display: flex; |
|||
flex-direction: row; |
|||
flex-wrap: wrap; |
|||
} |
|||
.x-spreadsheet-form-fields .x-spreadsheet-form-field { |
|||
flex: 0 1 auto; |
|||
} |
|||
.x-spreadsheet-form-fields .x-spreadsheet-form-field .label { |
|||
display: inline-block; |
|||
margin: 0 10px 0 0; |
|||
} |
|||
.x-spreadsheet-form-field { |
|||
display: block; |
|||
vertical-align: middle; |
|||
margin-left: 10px; |
|||
margin-bottom: 10px; |
|||
} |
|||
.x-spreadsheet-form-field:first-child { |
|||
margin-left: 0; |
|||
} |
|||
.x-spreadsheet-form-field.error .x-spreadsheet-form-select, |
|||
.x-spreadsheet-form-field.error input { |
|||
border-color: #f04134; |
|||
} |
|||
.x-spreadsheet-form-field .tip { |
|||
color: #f04134; |
|||
font-size: 0.9em; |
|||
} |
|||
.x-spreadsheet-dimmer { |
|||
display: none; |
|||
position: absolute; |
|||
top: 0 !important; |
|||
left: 0 !important; |
|||
width: 100%; |
|||
height: 100%; |
|||
text-align: center; |
|||
vertical-align: middle; |
|||
background-color: rgba(0, 0, 0, 0.6); |
|||
opacity: 0; |
|||
-webkit-animation-fill-mode: both; |
|||
animation-fill-mode: both; |
|||
-webkit-animation-duration: 0.5s; |
|||
animation-duration: 0.5s; |
|||
transition: background-color 0.5s linear; |
|||
user-select: none; |
|||
z-index: 1000; |
|||
} |
|||
.x-spreadsheet-dimmer.active { |
|||
display: block; |
|||
opacity: 1; |
|||
} |
|||
form fieldset { |
|||
border: none; |
|||
} |
|||
form fieldset label { |
|||
display: block; |
|||
margin-bottom: 0.5em; |
|||
font-size: 1em; |
|||
color: #666; |
|||
} |
|||
form fieldset select { |
|||
font-size: 1.1em; |
|||
width: 100%; |
|||
background-color: #fff; |
|||
border: none; |
|||
border-bottom: 2px solid #ddd; |
|||
padding: 0.5em 0.85em; |
|||
border-radius: 2px; |
|||
} |
|||
.x-spreadsheet-modal, |
|||
.x-spreadsheet-toast { |
|||
font-size: 13px; |
|||
position: fixed; |
|||
z-index: 1001; |
|||
text-align: left; |
|||
line-height: 1.25em; |
|||
min-width: 360px; |
|||
color: rgba(0, 0, 0, 0.87); |
|||
font-family: 'Lato', 'Source Sans Pro', Roboto, Helvetica, Arial, sans-serif; |
|||
border-radius: 4px; |
|||
border: 1px solid rgba(0, 0, 0, 0.1); |
|||
background-color: #fff; |
|||
background-clip: padding-box; |
|||
box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 8px; |
|||
} |
|||
.x-spreadsheet-toast { |
|||
background-color: rgba(255, 255, 255, 0.85); |
|||
} |
|||
.x-spreadsheet-modal-header, |
|||
.x-spreadsheet-toast-header { |
|||
font-weight: 600; |
|||
background-clip: padding-box; |
|||
background-color: rgba(255, 255, 255, 0.85); |
|||
border-bottom: 1px solid rgba(0, 0, 0, 0.05); |
|||
border-radius: 4px 4px 0 0; |
|||
} |
|||
|
|||
.x-spreadsheet-toast-header { |
|||
color: #F2711C; |
|||
} |
|||
.x-spreadsheet-modal-header { |
|||
border-bottom: 1px solid #e0e2e4; |
|||
background: rgba(0, 0, 0, 0.08); |
|||
font-size: 1.0785em; |
|||
} |
|||
.x-spreadsheet-modal-header, |
|||
.x-spreadsheet-modal-content, |
|||
.x-spreadsheet-toast-header, |
|||
.x-spreadsheet-toast-content { |
|||
padding: 0.75em 1em; |
|||
} |
|||
|
|||
.x-spreadsheet-menu li:first-child { |
|||
display: none; |
|||
} |
|||
|
|||
.vue-office-excel { |
|||
height: 100%; |
|||
} |
@ -0,0 +1,160 @@ |
|||
// node_modules/@vue/devtools-api/lib/esm/env.js
|
|||
function getDevtoolsGlobalHook() { |
|||
return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__; |
|||
} |
|||
function getTarget() { |
|||
return typeof navigator !== "undefined" && typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}; |
|||
} |
|||
var isProxyAvailable = typeof Proxy === "function"; |
|||
|
|||
// node_modules/@vue/devtools-api/lib/esm/const.js
|
|||
var HOOK_SETUP = "devtools-plugin:setup"; |
|||
var HOOK_PLUGIN_SETTINGS_SET = "plugin:settings:set"; |
|||
|
|||
// node_modules/@vue/devtools-api/lib/esm/time.js
|
|||
var supported; |
|||
var perf; |
|||
function isPerformanceSupported() { |
|||
var _a; |
|||
if (supported !== void 0) { |
|||
return supported; |
|||
} |
|||
if (typeof window !== "undefined" && window.performance) { |
|||
supported = true; |
|||
perf = window.performance; |
|||
} else if (typeof global !== "undefined" && ((_a = global.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) { |
|||
supported = true; |
|||
perf = global.perf_hooks.performance; |
|||
} else { |
|||
supported = false; |
|||
} |
|||
return supported; |
|||
} |
|||
function now() { |
|||
return isPerformanceSupported() ? perf.now() : Date.now(); |
|||
} |
|||
|
|||
// node_modules/@vue/devtools-api/lib/esm/proxy.js
|
|||
var ApiProxy = class { |
|||
constructor(plugin, hook) { |
|||
this.target = null; |
|||
this.targetQueue = []; |
|||
this.onQueue = []; |
|||
this.plugin = plugin; |
|||
this.hook = hook; |
|||
const defaultSettings = {}; |
|||
if (plugin.settings) { |
|||
for (const id in plugin.settings) { |
|||
const item = plugin.settings[id]; |
|||
defaultSettings[id] = item.defaultValue; |
|||
} |
|||
} |
|||
const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`; |
|||
let currentSettings = Object.assign({}, defaultSettings); |
|||
try { |
|||
const raw = localStorage.getItem(localSettingsSaveId); |
|||
const data = JSON.parse(raw); |
|||
Object.assign(currentSettings, data); |
|||
} catch (e) { |
|||
} |
|||
this.fallbacks = { |
|||
getSettings() { |
|||
return currentSettings; |
|||
}, |
|||
setSettings(value) { |
|||
try { |
|||
localStorage.setItem(localSettingsSaveId, JSON.stringify(value)); |
|||
} catch (e) { |
|||
} |
|||
currentSettings = value; |
|||
}, |
|||
now() { |
|||
return now(); |
|||
} |
|||
}; |
|||
if (hook) { |
|||
hook.on(HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => { |
|||
if (pluginId === this.plugin.id) { |
|||
this.fallbacks.setSettings(value); |
|||
} |
|||
}); |
|||
} |
|||
this.proxiedOn = new Proxy({}, { |
|||
get: (_target, prop) => { |
|||
if (this.target) { |
|||
return this.target.on[prop]; |
|||
} else { |
|||
return (...args) => { |
|||
this.onQueue.push({ |
|||
method: prop, |
|||
args |
|||
}); |
|||
}; |
|||
} |
|||
} |
|||
}); |
|||
this.proxiedTarget = new Proxy({}, { |
|||
get: (_target, prop) => { |
|||
if (this.target) { |
|||
return this.target[prop]; |
|||
} else if (prop === "on") { |
|||
return this.proxiedOn; |
|||
} else if (Object.keys(this.fallbacks).includes(prop)) { |
|||
return (...args) => { |
|||
this.targetQueue.push({ |
|||
method: prop, |
|||
args, |
|||
resolve: () => { |
|||
} |
|||
}); |
|||
return this.fallbacks[prop](...args); |
|||
}; |
|||
} else { |
|||
return (...args) => { |
|||
return new Promise((resolve) => { |
|||
this.targetQueue.push({ |
|||
method: prop, |
|||
args, |
|||
resolve |
|||
}); |
|||
}); |
|||
}; |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
async setRealTarget(target) { |
|||
this.target = target; |
|||
for (const item of this.onQueue) { |
|||
this.target.on[item.method](...item.args); |
|||
} |
|||
for (const item of this.targetQueue) { |
|||
item.resolve(await this.target[item.method](...item.args)); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// node_modules/@vue/devtools-api/lib/esm/index.js
|
|||
function setupDevtoolsPlugin(pluginDescriptor, setupFn) { |
|||
const descriptor = pluginDescriptor; |
|||
const target = getTarget(); |
|||
const hook = getDevtoolsGlobalHook(); |
|||
const enableProxy = isProxyAvailable && descriptor.enableEarlyProxy; |
|||
if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) { |
|||
hook.emit(HOOK_SETUP, pluginDescriptor, setupFn); |
|||
} else { |
|||
const proxy = enableProxy ? new ApiProxy(descriptor, hook) : null; |
|||
const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || []; |
|||
list.push({ |
|||
pluginDescriptor: descriptor, |
|||
setupFn, |
|||
proxy |
|||
}); |
|||
if (proxy) |
|||
setupFn(proxy.proxiedTarget); |
|||
} |
|||
} |
|||
|
|||
export { |
|||
setupDevtoolsPlugin |
|||
}; |
@ -0,0 +1,8 @@ |
|||
/** |
|||
* Bundled by jsDelivr using Rollup v2.79.1 and Terser v5.17.1. |
|||
* Original file: /npm/detect-it@4.0.1/dist/detect-it.esm.js |
|||
* |
|||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
|||
*/ |
|||
var e="undefined"!=typeof window?window:{screen:{},navigator:{}},n=(e.matchMedia||function(){return{matches:!1}}).bind(e),t=!1,o={get passive(){return t=!0}},i=function(){};e.addEventListener&&e.addEventListener("p",i,o),e.removeEventListener&&e.removeEventListener("p",i,!1);var r=t,a="PointerEvent"in e,s="ontouchstart"in e,c=s||"TouchEvent"in e&&n("(any-pointer: coarse)").matches,h=(e.navigator.maxTouchPoints||0)>0||c,u=e.navigator.userAgent||"",m=n("(pointer: coarse)").matches&&/iPad|Macintosh/.test(u)&&Math.min(e.screen.width||0,e.screen.height||0)>=768,v=(n("(pointer: coarse)").matches||!n("(pointer: fine)").matches&&s)&&!/Windows.*Firefox/.test(u),d=n("(any-pointer: fine)").matches||n("(any-hover: hover)").matches||m||!s,p=!h||!d&&v?h?"touchOnly":"mouseOnly":"hybrid",y="mouseOnly"===p?"mouse":"touchOnly"===p||v?"touch":"mouse";export{p as deviceType,y as primaryInput,r as supportsPassiveEvents,a as supportsPointerEvents,c as supportsTouchEvents};export default null; |
|||
//# sourceMappingURL=/sm/4280e12bc6c9669987adcde477eb6347c379a3a324091a23187d02e5284db1bb.map
|
@ -0,0 +1,2 @@ |
|||
/*! Element Plus v2.3.6 */var e={name:"en",el:{colorpicker:{confirm:"OK",clear:"Clear",defaultLabel:"color picker",description:"current color is {color}. press enter to select a new color."},datepicker:{now:"Now",today:"Today",cancel:"Cancel",clear:"Clear",confirm:"OK",dateTablePrompt:"Use the arrow keys and enter to select the day of the month",monthTablePrompt:"Use the arrow keys and enter to select the month",yearTablePrompt:"Use the arrow keys and enter to select the year",selectedDate:"Selected date",selectDate:"Select date",selectTime:"Select time",startDate:"Start Date",startTime:"Start Time",endDate:"End Date",endTime:"End Time",prevYear:"Previous Year",nextYear:"Next Year",prevMonth:"Previous Month",nextMonth:"Next Month",year:"",month1:"January",month2:"February",month3:"March",month4:"April",month5:"May",month6:"June",month7:"July",month8:"August",month9:"September",month10:"October",month11:"November",month12:"December",week:"week",weeks:{sun:"Sun",mon:"Mon",tue:"Tue",wed:"Wed",thu:"Thu",fri:"Fri",sat:"Sat"},weeksFull:{sun:"Sunday",mon:"Monday",tue:"Tuesday",wed:"Wednesday",thu:"Thursday",fri:"Friday",sat:"Saturday"},months:{jan:"Jan",feb:"Feb",mar:"Mar",apr:"Apr",may:"May",jun:"Jun",jul:"Jul",aug:"Aug",sep:"Sep",oct:"Oct",nov:"Nov",dec:"Dec"}},inputNumber:{decrease:"decrease number",increase:"increase number"},select:{loading:"Loading",noMatch:"No matching data",noData:"No data",placeholder:"Select"},dropdown:{toggleDropdown:"Toggle Dropdown"},cascader:{noMatch:"No matching data",loading:"Loading",placeholder:"Select",noData:"No data"},pagination:{goto:"Go to",pagesize:"/page",total:"Total {total}",pageClassifier:"",page:"Page",prev:"Go to previous page",next:"Go to next page",currentPage:"page {pager}",prevPages:"Previous {pager} pages",nextPages:"Next {pager} pages",deprecationWarning:"Deprecated usages detected, please refer to the el-pagination documentation for more details"},dialog:{close:"Close this dialog"},drawer:{close:"Close this dialog"},messagebox:{title:"Message",confirm:"OK",cancel:"Cancel",error:"Illegal input",close:"Close this dialog"},upload:{deleteTip:"press delete to remove",delete:"Delete",preview:"Preview",continue:"Continue"},slider:{defaultLabel:"slider between {min} and {max}",defaultRangeStartLabel:"pick start value",defaultRangeEndLabel:"pick end value"},table:{emptyText:"No Data",confirmFilter:"Confirm",resetFilter:"Reset",clearFilter:"All",sumText:"Sum"},tree:{emptyText:"No Data"},transfer:{noMatch:"No matching data",noData:"No data",titles:["List 1","List 2"],filterPlaceholder:"Enter keyword",noCheckedFormat:"{total} items",hasCheckedFormat:"{checked}/{total} checked"},image:{error:"FAILED"},pageHeader:{title:"Back"},popconfirm:{confirmButtonText:"Yes",cancelButtonText:"No"}}};export{e as default}; |
|||
//# sourceMappingURL=en.min.mjs.map
|
@ -0,0 +1,2 @@ |
|||
/*! Element Plus v2.3.4 */var u={name:"zh-cn",el:{colorpicker:{confirm:"\u786E\u5B9A",clear:"\u6E05\u7A7A"},datepicker:{now:"\u6B64\u523B",today:"\u4ECA\u5929",cancel:"\u53D6\u6D88",clear:"\u6E05\u7A7A",confirm:"\u786E\u5B9A",selectDate:"\u9009\u62E9\u65E5\u671F",selectTime:"\u9009\u62E9\u65F6\u95F4",startDate:"\u5F00\u59CB\u65E5\u671F",startTime:"\u5F00\u59CB\u65F6\u95F4",endDate:"\u7ED3\u675F\u65E5\u671F",endTime:"\u7ED3\u675F\u65F6\u95F4",prevYear:"\u524D\u4E00\u5E74",nextYear:"\u540E\u4E00\u5E74",prevMonth:"\u4E0A\u4E2A\u6708",nextMonth:"\u4E0B\u4E2A\u6708",year:"\u5E74",month1:"1 \u6708",month2:"2 \u6708",month3:"3 \u6708",month4:"4 \u6708",month5:"5 \u6708",month6:"6 \u6708",month7:"7 \u6708",month8:"8 \u6708",month9:"9 \u6708",month10:"10 \u6708",month11:"11 \u6708",month12:"12 \u6708",weeks:{sun:"\u65E5",mon:"\u4E00",tue:"\u4E8C",wed:"\u4E09",thu:"\u56DB",fri:"\u4E94",sat:"\u516D"},months:{jan:"\u4E00\u6708",feb:"\u4E8C\u6708",mar:"\u4E09\u6708",apr:"\u56DB\u6708",may:"\u4E94\u6708",jun:"\u516D\u6708",jul:"\u4E03\u6708",aug:"\u516B\u6708",sep:"\u4E5D\u6708",oct:"\u5341\u6708",nov:"\u5341\u4E00\u6708",dec:"\u5341\u4E8C\u6708"}},select:{loading:"\u52A0\u8F7D\u4E2D",noMatch:"\u65E0\u5339\u914D\u6570\u636E",noData:"\u65E0\u6570\u636E",placeholder:"\u8BF7\u9009\u62E9"},cascader:{noMatch:"\u65E0\u5339\u914D\u6570\u636E",loading:"\u52A0\u8F7D\u4E2D",placeholder:"\u8BF7\u9009\u62E9",noData:"\u6682\u65E0\u6570\u636E"},pagination:{goto:"\u524D\u5F80",pagesize:"\u6761/\u9875",total:"\u5171 {total} \u6761",pageClassifier:"\u9875",page:"\u9875",prev:"\u4E0A\u4E00\u9875",next:"\u4E0B\u4E00\u9875",currentPage:"\u7B2C {pager} \u9875",prevPages:"\u5411\u524D {pager} \u9875",nextPages:"\u5411\u540E {pager} \u9875",deprecationWarning:"\u4F60\u4F7F\u7528\u4E86\u4E00\u4E9B\u5DF2\u88AB\u5E9F\u5F03\u7684\u7528\u6CD5\uFF0C\u8BF7\u53C2\u8003 el-pagination \u7684\u5B98\u65B9\u6587\u6863"},messagebox:{title:"\u63D0\u793A",confirm:"\u786E\u5B9A",cancel:"\u53D6\u6D88",error:"\u8F93\u5165\u7684\u6570\u636E\u4E0D\u5408\u6CD5!"},upload:{deleteTip:"\u6309 delete \u952E\u53EF\u5220\u9664",delete:"\u5220\u9664",preview:"\u67E5\u770B\u56FE\u7247",continue:"\u7EE7\u7EED\u4E0A\u4F20"},table:{emptyText:"\u6682\u65E0\u6570\u636E",confirmFilter:"\u7B5B\u9009",resetFilter:"\u91CD\u7F6E",clearFilter:"\u5168\u90E8",sumText:"\u5408\u8BA1"},tree:{emptyText:"\u6682\u65E0\u6570\u636E"},transfer:{noMatch:"\u65E0\u5339\u914D\u6570\u636E",noData:"\u65E0\u6570\u636E",titles:["\u5217\u8868 1","\u5217\u8868 2"],filterPlaceholder:"\u8BF7\u8F93\u5165\u641C\u7D22\u5185\u5BB9",noCheckedFormat:"\u5171 {total} \u9879",hasCheckedFormat:"\u5DF2\u9009 {checked}/{total} \u9879"},image:{error:"\u52A0\u8F7D\u5931\u8D25"},pageHeader:{title:"\u8FD4\u56DE"},popconfirm:{confirmButtonText:"\u786E\u5B9A",cancelButtonText:"\u53D6\u6D88"}}};export{u as default}; |
|||
//# sourceMappingURL=zh-cn.min.mjs.map
|
@ -0,0 +1 @@ |
|||
html.dark{color-scheme:dark;--el-color-primary:#409eff;--el-color-primary-light-3:#3375b9;--el-color-primary-light-5:#2a598a;--el-color-primary-light-7:#213d5b;--el-color-primary-light-8:#1d3043;--el-color-primary-light-9:#18222c;--el-color-primary-dark-2:#66b1ff;--el-color-success:#67c23a;--el-color-success-light-3:#4e8e2f;--el-color-success-light-5:#3e6b27;--el-color-success-light-7:#2d481f;--el-color-success-light-8:#25371c;--el-color-success-light-9:#1c2518;--el-color-success-dark-2:#85ce61;--el-color-warning:#e6a23c;--el-color-warning-light-3:#a77730;--el-color-warning-light-5:#7d5b28;--el-color-warning-light-7:#533f20;--el-color-warning-light-8:#3e301c;--el-color-warning-light-9:#292218;--el-color-warning-dark-2:#ebb563;--el-color-danger:#f56c6c;--el-color-danger-light-3:#b25252;--el-color-danger-light-5:#854040;--el-color-danger-light-7:#582e2e;--el-color-danger-light-8:#412626;--el-color-danger-light-9:#2b1d1d;--el-color-danger-dark-2:#f78989;--el-color-error:#f56c6c;--el-color-error-light-3:#b25252;--el-color-error-light-5:#854040;--el-color-error-light-7:#582e2e;--el-color-error-light-8:#412626;--el-color-error-light-9:#2b1d1d;--el-color-error-dark-2:#f78989;--el-color-info:#909399;--el-color-info-light-3:#6b6d71;--el-color-info-light-5:#525457;--el-color-info-light-7:#393a3c;--el-color-info-light-8:#2d2d2f;--el-color-info-light-9:#202121;--el-color-info-dark-2:#a6a9ad;--el-box-shadow:0px 12px 32px 4px rgba(0, 0, 0, 0.36),0px 8px 20px rgba(0, 0, 0, 0.72);--el-box-shadow-light:0px 0px 12px rgba(0, 0, 0, 0.72);--el-box-shadow-lighter:0px 0px 6px rgba(0, 0, 0, 0.72);--el-box-shadow-dark:0px 16px 48px 16px rgba(0, 0, 0, 0.72),0px 12px 32px #000000,0px 8px 16px -8px #000000;--el-bg-color-page:#0a0a0a;--el-bg-color:#141414;--el-bg-color-overlay:#1d1e1f;--el-text-color-primary:#E5EAF3;--el-text-color-regular:#CFD3DC;--el-text-color-secondary:#A3A6AD;--el-text-color-placeholder:#8D9095;--el-text-color-disabled:#6C6E72;--el-border-color-darker:#636466;--el-border-color-dark:#58585B;--el-border-color:#4C4D4F;--el-border-color-light:#414243;--el-border-color-lighter:#363637;--el-border-color-extra-light:#2B2B2C;--el-fill-color-darker:#424243;--el-fill-color-dark:#39393A;--el-fill-color:#303030;--el-fill-color-light:#262727;--el-fill-color-lighter:#1D1D1D;--el-fill-color-extra-light:#191919;--el-fill-color-blank:transparent;--el-mask-color:rgba(0, 0, 0, 0.8);--el-mask-color-extra-light:rgba(0, 0, 0, 0.3)}html.dark .el-button{--el-button-disabled-text-color:rgba(255, 255, 255, 0.5)}html.dark .el-card{--el-card-bg-color:var(--el-bg-color-overlay)}html.dark .el-empty{--el-empty-fill-color-0:var(--el-color-black);--el-empty-fill-color-1:#4b4b52;--el-empty-fill-color-2:#36383d;--el-empty-fill-color-3:#1e1e20;--el-empty-fill-color-4:#262629;--el-empty-fill-color-5:#202124;--el-empty-fill-color-6:#212224;--el-empty-fill-color-7:#1b1c1f;--el-empty-fill-color-8:#1c1d1f;--el-empty-fill-color-9:#18181a} |
@ -0,0 +1,881 @@ |
|||
/** |
|||
* Minified by jsDelivr using clean-css v5.2.2. |
|||
* Original file: /npm/github-markdown-css@5.1.0/github-markdown.css |
|||
* |
|||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files |
|||
*/ |
|||
.markdown-body { |
|||
color-scheme: light; |
|||
--color-prettylights-syntax-comment: #6e7781; |
|||
--color-prettylights-syntax-constant: #0550ae; |
|||
--color-prettylights-syntax-entity: #8250df; |
|||
--color-prettylights-syntax-storage-modifier-import: #24292f; |
|||
--color-prettylights-syntax-entity-tag: #116329; |
|||
--color-prettylights-syntax-keyword: #cf222e; |
|||
--color-prettylights-syntax-string: #0a3069; |
|||
--color-prettylights-syntax-variable: #953800; |
|||
--color-prettylights-syntax-brackethighlighter-unmatched: #82071e; |
|||
--color-prettylights-syntax-invalid-illegal-text: #f6f8fa; |
|||
--color-prettylights-syntax-invalid-illegal-bg: #82071e; |
|||
--color-prettylights-syntax-carriage-return-text: #f6f8fa; |
|||
--color-prettylights-syntax-carriage-return-bg: #cf222e; |
|||
--color-prettylights-syntax-string-regexp: #116329; |
|||
--color-prettylights-syntax-markup-list: #3b2300; |
|||
--color-prettylights-syntax-markup-heading: #0550ae; |
|||
--color-prettylights-syntax-markup-italic: #24292f; |
|||
--color-prettylights-syntax-markup-bold: #24292f; |
|||
--color-prettylights-syntax-markup-deleted-text: #82071e; |
|||
--color-prettylights-syntax-markup-deleted-bg: #ffebe9; |
|||
--color-prettylights-syntax-markup-inserted-text: #116329; |
|||
--color-prettylights-syntax-markup-inserted-bg: #dafbe1; |
|||
--color-prettylights-syntax-markup-changed-text: #953800; |
|||
--color-prettylights-syntax-markup-changed-bg: #ffd8b5; |
|||
--color-prettylights-syntax-markup-ignored-text: #eaeef2; |
|||
--color-prettylights-syntax-markup-ignored-bg: #0550ae; |
|||
--color-prettylights-syntax-meta-diff-range: #8250df; |
|||
--color-prettylights-syntax-brackethighlighter-angle: #57606a; |
|||
--color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f; |
|||
--color-prettylights-syntax-constant-other-reference-link: #0a3069; |
|||
--color-fg-default: #24292f; |
|||
--color-fg-muted: #57606a; |
|||
--color-fg-subtle: #6e7781; |
|||
--color-canvas-default: #ffffff; |
|||
--color-canvas-subtle: #f6f8fa; |
|||
--color-border-default: #d0d7de; |
|||
--color-border-muted: hsla(210, 18%, 87%, 1); |
|||
--color-neutral-muted: rgba(175, 184, 193, 0.2); |
|||
--color-accent-fg: #0969da; |
|||
--color-accent-emphasis: #0969da; |
|||
--color-attention-subtle: #fff8c5; |
|||
--color-danger-fg: #cf222e; |
|||
} |
|||
|
|||
html.dark .markdown-body { |
|||
color-scheme: dark; |
|||
--color-prettylights-syntax-comment: #8b949e; |
|||
--color-prettylights-syntax-constant: #79c0ff; |
|||
--color-prettylights-syntax-entity: #d2a8ff; |
|||
--color-prettylights-syntax-storage-modifier-import: #c9d1d9; |
|||
--color-prettylights-syntax-entity-tag: #7ee787; |
|||
--color-prettylights-syntax-keyword: #ff7b72; |
|||
--color-prettylights-syntax-string: #a5d6ff; |
|||
--color-prettylights-syntax-variable: #ffa657; |
|||
--color-prettylights-syntax-brackethighlighter-unmatched: #f85149; |
|||
--color-prettylights-syntax-invalid-illegal-text: #f0f6fc; |
|||
--color-prettylights-syntax-invalid-illegal-bg: #8e1519; |
|||
--color-prettylights-syntax-carriage-return-text: #f0f6fc; |
|||
--color-prettylights-syntax-carriage-return-bg: #b62324; |
|||
--color-prettylights-syntax-string-regexp: #7ee787; |
|||
--color-prettylights-syntax-markup-list: #f2cc60; |
|||
--color-prettylights-syntax-markup-heading: #1f6feb; |
|||
--color-prettylights-syntax-markup-italic: #c9d1d9; |
|||
--color-prettylights-syntax-markup-bold: #c9d1d9; |
|||
--color-prettylights-syntax-markup-deleted-text: #ffdcd7; |
|||
--color-prettylights-syntax-markup-deleted-bg: #67060c; |
|||
--color-prettylights-syntax-markup-inserted-text: #aff5b4; |
|||
--color-prettylights-syntax-markup-inserted-bg: #033a16; |
|||
--color-prettylights-syntax-markup-changed-text: #ffdfb6; |
|||
--color-prettylights-syntax-markup-changed-bg: #5a1e02; |
|||
--color-prettylights-syntax-markup-ignored-text: #c9d1d9; |
|||
--color-prettylights-syntax-markup-ignored-bg: #1158c7; |
|||
--color-prettylights-syntax-meta-diff-range: #d2a8ff; |
|||
--color-prettylights-syntax-brackethighlighter-angle: #8b949e; |
|||
--color-prettylights-syntax-sublimelinter-gutter-mark: #484f58; |
|||
--color-prettylights-syntax-constant-other-reference-link: #a5d6ff; |
|||
--color-fg-default: #c9d1d9; |
|||
--color-fg-muted: #8b949e; |
|||
--color-fg-subtle: #484f58; |
|||
--color-canvas-default: #0d1117; |
|||
--color-canvas-subtle: #161b22; |
|||
--color-border-default: #30363d; |
|||
--color-border-muted: #21262d; |
|||
--color-neutral-muted: rgba(110, 118, 129, 0.4); |
|||
--color-accent-fg: #58a6ff; |
|||
--color-accent-emphasis: #1f6feb; |
|||
--color-attention-subtle: rgba(187, 128, 9, 0.15); |
|||
--color-danger-fg: #f85149; |
|||
} |
|||
|
|||
.markdown-body { |
|||
-ms-text-size-adjust: 100%; |
|||
-webkit-text-size-adjust: 100%; |
|||
margin: 0; |
|||
color: var(--color-fg-default); |
|||
background-color: var(--color-canvas-default); |
|||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", |
|||
"Segoe UI Emoji"; |
|||
font-size: 16px; |
|||
line-height: 1.5; |
|||
word-wrap: break-word; |
|||
} |
|||
.markdown-body .octicon { |
|||
display: inline-block; |
|||
fill: currentColor; |
|||
vertical-align: text-bottom; |
|||
} |
|||
.markdown-body h1:hover .anchor .octicon-link:before, |
|||
.markdown-body h2:hover .anchor .octicon-link:before, |
|||
.markdown-body h3:hover .anchor .octicon-link:before, |
|||
.markdown-body h4:hover .anchor .octicon-link:before, |
|||
.markdown-body h5:hover .anchor .octicon-link:before, |
|||
.markdown-body h6:hover .anchor .octicon-link:before { |
|||
width: 16px; |
|||
height: 16px; |
|||
content: " "; |
|||
display: inline-block; |
|||
background-color: currentColor; |
|||
-webkit-mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>"); |
|||
mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' version='1.1' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>"); |
|||
} |
|||
.markdown-body details, |
|||
.markdown-body figcaption, |
|||
.markdown-body figure { |
|||
display: block; |
|||
} |
|||
.markdown-body summary { |
|||
display: list-item; |
|||
} |
|||
.markdown-body [hidden] { |
|||
display: none !important; |
|||
} |
|||
.markdown-body a { |
|||
background-color: transparent; |
|||
color: var(--color-accent-fg); |
|||
text-decoration: none; |
|||
} |
|||
.markdown-body a:active, |
|||
.markdown-body a:hover { |
|||
outline-width: 0; |
|||
} |
|||
.markdown-body abbr[title] { |
|||
border-bottom: none; |
|||
text-decoration: underline dotted; |
|||
} |
|||
.markdown-body b, |
|||
.markdown-body strong { |
|||
font-weight: 600; |
|||
} |
|||
.markdown-body dfn { |
|||
font-style: italic; |
|||
} |
|||
.markdown-body h1 { |
|||
margin: 0.67em 0; |
|||
font-weight: 600; |
|||
padding-bottom: 0.3em; |
|||
font-size: 2em; |
|||
border-bottom: 1px solid var(--color-border-muted); |
|||
} |
|||
.markdown-body mark { |
|||
background-color: var(--color-attention-subtle); |
|||
color: var(--color-text-primary); |
|||
} |
|||
.markdown-body small { |
|||
font-size: 90%; |
|||
} |
|||
.markdown-body sub, |
|||
.markdown-body sup { |
|||
font-size: 75%; |
|||
line-height: 0; |
|||
position: relative; |
|||
vertical-align: baseline; |
|||
} |
|||
.markdown-body sub { |
|||
bottom: -0.25em; |
|||
} |
|||
.markdown-body sup { |
|||
top: -0.5em; |
|||
} |
|||
.markdown-body img { |
|||
border-style: none; |
|||
max-width: 100%; |
|||
box-sizing: content-box; |
|||
background-color: var(--color-canvas-default); |
|||
} |
|||
.markdown-body code, |
|||
.markdown-body kbd, |
|||
.markdown-body pre, |
|||
.markdown-body samp { |
|||
font-family: monospace, monospace; |
|||
font-size: 1em; |
|||
} |
|||
.markdown-body figure { |
|||
margin: 1em 40px; |
|||
} |
|||
.markdown-body hr { |
|||
box-sizing: content-box; |
|||
overflow: hidden; |
|||
background: 0 0; |
|||
border-bottom: 1px solid var(--color-border-muted); |
|||
height: 0.25em; |
|||
padding: 0; |
|||
margin: 24px 0; |
|||
background-color: var(--color-border-default); |
|||
border: 0; |
|||
} |
|||
.markdown-body input { |
|||
font: inherit; |
|||
margin: 0; |
|||
overflow: visible; |
|||
font-family: inherit; |
|||
font-size: inherit; |
|||
line-height: inherit; |
|||
} |
|||
.markdown-body [type="button"], |
|||
.markdown-body [type="reset"], |
|||
.markdown-body [type="submit"] { |
|||
-webkit-appearance: button; |
|||
} |
|||
.markdown-body [type="button"]::-moz-focus-inner, |
|||
.markdown-body [type="reset"]::-moz-focus-inner, |
|||
.markdown-body [type="submit"]::-moz-focus-inner { |
|||
border-style: none; |
|||
padding: 0; |
|||
} |
|||
.markdown-body [type="button"]:-moz-focusring, |
|||
.markdown-body [type="reset"]:-moz-focusring, |
|||
.markdown-body [type="submit"]:-moz-focusring { |
|||
outline: 1px dotted ButtonText; |
|||
} |
|||
.markdown-body [type="checkbox"], |
|||
.markdown-body [type="radio"] { |
|||
box-sizing: border-box; |
|||
padding: 0; |
|||
} |
|||
.markdown-body [type="number"]::-webkit-inner-spin-button, |
|||
.markdown-body [type="number"]::-webkit-outer-spin-button { |
|||
height: auto; |
|||
} |
|||
.markdown-body [type="search"] { |
|||
-webkit-appearance: textfield; |
|||
outline-offset: -2px; |
|||
} |
|||
.markdown-body [type="search"]::-webkit-search-cancel-button, |
|||
.markdown-body [type="search"]::-webkit-search-decoration { |
|||
-webkit-appearance: none; |
|||
} |
|||
.markdown-body ::-webkit-input-placeholder { |
|||
color: inherit; |
|||
opacity: 0.54; |
|||
} |
|||
.markdown-body ::-webkit-file-upload-button { |
|||
-webkit-appearance: button; |
|||
font: inherit; |
|||
} |
|||
.markdown-body a:hover { |
|||
text-decoration: underline; |
|||
} |
|||
.markdown-body hr::before { |
|||
display: table; |
|||
content: ""; |
|||
} |
|||
.markdown-body hr::after { |
|||
display: table; |
|||
clear: both; |
|||
content: ""; |
|||
} |
|||
.markdown-body table { |
|||
border-spacing: 0; |
|||
border-collapse: collapse; |
|||
display: block; |
|||
width: max-content; |
|||
max-width: 100%; |
|||
overflow: auto; |
|||
} |
|||
.markdown-body td, |
|||
.markdown-body th { |
|||
padding: 0; |
|||
} |
|||
.markdown-body details summary { |
|||
cursor: pointer; |
|||
} |
|||
.markdown-body details:not([open]) > :not(summary) { |
|||
display: none !important; |
|||
} |
|||
.markdown-body kbd { |
|||
display: inline-block; |
|||
padding: 3px 5px; |
|||
font: 11px ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; |
|||
line-height: 10px; |
|||
color: var(--color-fg-default); |
|||
vertical-align: middle; |
|||
background-color: var(--color-canvas-subtle); |
|||
border: solid 1px var(--color-neutral-muted); |
|||
border-bottom-color: var(--color-neutral-muted); |
|||
border-radius: 6px; |
|||
box-shadow: inset 0 -1px 0 var(--color-neutral-muted); |
|||
} |
|||
.markdown-body h1, |
|||
.markdown-body h2, |
|||
.markdown-body h3, |
|||
.markdown-body h4, |
|||
.markdown-body h5, |
|||
.markdown-body h6 { |
|||
margin-top: 24px; |
|||
margin-bottom: 16px; |
|||
font-weight: 600; |
|||
line-height: 1.25; |
|||
} |
|||
.markdown-body h2 { |
|||
font-weight: 600; |
|||
padding-bottom: 0.3em; |
|||
font-size: 1.5em; |
|||
border-bottom: 1px solid var(--color-border-muted); |
|||
} |
|||
.markdown-body h3 { |
|||
font-weight: 600; |
|||
font-size: 1.25em; |
|||
} |
|||
.markdown-body h4 { |
|||
font-weight: 600; |
|||
font-size: 1em; |
|||
} |
|||
.markdown-body h5 { |
|||
font-weight: 600; |
|||
font-size: 0.875em; |
|||
} |
|||
.markdown-body h6 { |
|||
font-weight: 600; |
|||
font-size: 0.85em; |
|||
color: var(--color-fg-muted); |
|||
} |
|||
.markdown-body p { |
|||
margin-top: 0; |
|||
margin-bottom: 10px; |
|||
} |
|||
.markdown-body blockquote { |
|||
margin: 0; |
|||
padding: 0 1em; |
|||
color: var(--color-fg-muted); |
|||
border-left: 0.25em solid var(--color-border-default); |
|||
} |
|||
.markdown-body ol, |
|||
.markdown-body ul { |
|||
margin-top: 0; |
|||
margin-bottom: 0; |
|||
padding-left: 2em; |
|||
} |
|||
.markdown-body ol ol, |
|||
.markdown-body ul ol { |
|||
list-style-type: lower-roman; |
|||
} |
|||
.markdown-body ol ol ol, |
|||
.markdown-body ol ul ol, |
|||
.markdown-body ul ol ol, |
|||
.markdown-body ul ul ol { |
|||
list-style-type: lower-alpha; |
|||
} |
|||
.markdown-body dd { |
|||
margin-left: 0; |
|||
} |
|||
.markdown-body code, |
|||
.markdown-body tt { |
|||
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; |
|||
font-size: 12px; |
|||
} |
|||
.markdown-body pre { |
|||
margin-top: 0; |
|||
margin-bottom: 0; |
|||
font-family: ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; |
|||
font-size: 12px; |
|||
word-wrap: normal; |
|||
} |
|||
.markdown-body .octicon { |
|||
display: inline-block; |
|||
overflow: visible !important; |
|||
vertical-align: text-bottom; |
|||
fill: currentColor; |
|||
} |
|||
.markdown-body ::placeholder { |
|||
color: var(--color-fg-subtle); |
|||
opacity: 1; |
|||
} |
|||
.markdown-body input::-webkit-inner-spin-button, |
|||
.markdown-body input::-webkit-outer-spin-button { |
|||
margin: 0; |
|||
-webkit-appearance: none; |
|||
appearance: none; |
|||
} |
|||
.markdown-body .pl-c { |
|||
color: var(--color-prettylights-syntax-comment); |
|||
} |
|||
.markdown-body .pl-c1, |
|||
.markdown-body .pl-s .pl-v { |
|||
color: var(--color-prettylights-syntax-constant); |
|||
} |
|||
.markdown-body .pl-e, |
|||
.markdown-body .pl-en { |
|||
color: var(--color-prettylights-syntax-entity); |
|||
} |
|||
.markdown-body .pl-s .pl-s1, |
|||
.markdown-body .pl-smi { |
|||
color: var(--color-prettylights-syntax-storage-modifier-import); |
|||
} |
|||
.markdown-body .pl-ent { |
|||
color: var(--color-prettylights-syntax-entity-tag); |
|||
} |
|||
.markdown-body .pl-k { |
|||
color: var(--color-prettylights-syntax-keyword); |
|||
} |
|||
.markdown-body .pl-pds, |
|||
.markdown-body .pl-s, |
|||
.markdown-body .pl-s .pl-pse .pl-s1, |
|||
.markdown-body .pl-sr, |
|||
.markdown-body .pl-sr .pl-cce, |
|||
.markdown-body .pl-sr .pl-sra, |
|||
.markdown-body .pl-sr .pl-sre { |
|||
color: var(--color-prettylights-syntax-string); |
|||
} |
|||
.markdown-body .pl-smw, |
|||
.markdown-body .pl-v { |
|||
color: var(--color-prettylights-syntax-variable); |
|||
} |
|||
.markdown-body .pl-bu { |
|||
color: var(--color-prettylights-syntax-brackethighlighter-unmatched); |
|||
} |
|||
.markdown-body .pl-ii { |
|||
color: var(--color-prettylights-syntax-invalid-illegal-text); |
|||
background-color: var(--color-prettylights-syntax-invalid-illegal-bg); |
|||
} |
|||
.markdown-body .pl-c2 { |
|||
color: var(--color-prettylights-syntax-carriage-return-text); |
|||
background-color: var(--color-prettylights-syntax-carriage-return-bg); |
|||
} |
|||
.markdown-body .pl-sr .pl-cce { |
|||
font-weight: 700; |
|||
color: var(--color-prettylights-syntax-string-regexp); |
|||
} |
|||
.markdown-body .pl-ml { |
|||
color: var(--color-prettylights-syntax-markup-list); |
|||
} |
|||
.markdown-body .pl-mh, |
|||
.markdown-body .pl-mh .pl-en, |
|||
.markdown-body .pl-ms { |
|||
font-weight: 700; |
|||
color: var(--color-prettylights-syntax-markup-heading); |
|||
} |
|||
.markdown-body .pl-mi { |
|||
font-style: italic; |
|||
color: var(--color-prettylights-syntax-markup-italic); |
|||
} |
|||
.markdown-body .pl-mb { |
|||
font-weight: 700; |
|||
color: var(--color-prettylights-syntax-markup-bold); |
|||
} |
|||
.markdown-body .pl-md { |
|||
color: var(--color-prettylights-syntax-markup-deleted-text); |
|||
background-color: var(--color-prettylights-syntax-markup-deleted-bg); |
|||
} |
|||
.markdown-body .pl-mi1 { |
|||
color: var(--color-prettylights-syntax-markup-inserted-text); |
|||
background-color: var(--color-prettylights-syntax-markup-inserted-bg); |
|||
} |
|||
.markdown-body .pl-mc { |
|||
color: var(--color-prettylights-syntax-markup-changed-text); |
|||
background-color: var(--color-prettylights-syntax-markup-changed-bg); |
|||
} |
|||
.markdown-body .pl-mi2 { |
|||
color: var(--color-prettylights-syntax-markup-ignored-text); |
|||
background-color: var(--color-prettylights-syntax-markup-ignored-bg); |
|||
} |
|||
.markdown-body .pl-mdr { |
|||
font-weight: 700; |
|||
color: var(--color-prettylights-syntax-meta-diff-range); |
|||
} |
|||
.markdown-body .pl-ba { |
|||
color: var(--color-prettylights-syntax-brackethighlighter-angle); |
|||
} |
|||
.markdown-body .pl-sg { |
|||
color: var(--color-prettylights-syntax-sublimelinter-gutter-mark); |
|||
} |
|||
.markdown-body .pl-corl { |
|||
text-decoration: underline; |
|||
color: var(--color-prettylights-syntax-constant-other-reference-link); |
|||
} |
|||
.markdown-body [data-catalyst] { |
|||
display: block; |
|||
} |
|||
.markdown-body g-emoji { |
|||
font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; |
|||
font-size: 1em; |
|||
font-style: normal !important; |
|||
font-weight: 400; |
|||
line-height: 1; |
|||
vertical-align: -0.075em; |
|||
} |
|||
.markdown-body g-emoji img { |
|||
width: 1em; |
|||
height: 1em; |
|||
} |
|||
.markdown-body::before { |
|||
display: table; |
|||
content: ""; |
|||
} |
|||
.markdown-body::after { |
|||
display: table; |
|||
clear: both; |
|||
content: ""; |
|||
} |
|||
.markdown-body > :first-child { |
|||
margin-top: 0 !important; |
|||
} |
|||
.markdown-body > :last-child { |
|||
margin-bottom: 0 !important; |
|||
} |
|||
.markdown-body a:not([href]) { |
|||
color: inherit; |
|||
text-decoration: none; |
|||
} |
|||
.markdown-body .absent { |
|||
color: var(--color-danger-fg); |
|||
} |
|||
.markdown-body .anchor { |
|||
float: left; |
|||
padding-right: 4px; |
|||
margin-left: -20px; |
|||
line-height: 1; |
|||
} |
|||
.markdown-body .anchor:focus { |
|||
outline: 0; |
|||
} |
|||
.markdown-body blockquote, |
|||
.markdown-body details, |
|||
.markdown-body dl, |
|||
.markdown-body ol, |
|||
.markdown-body p, |
|||
.markdown-body pre, |
|||
.markdown-body table, |
|||
.markdown-body ul { |
|||
margin-top: 0; |
|||
margin-bottom: 16px; |
|||
} |
|||
.markdown-body blockquote > :first-child { |
|||
margin-top: 0; |
|||
} |
|||
.markdown-body blockquote > :last-child { |
|||
margin-bottom: 0; |
|||
} |
|||
.markdown-body sup > a::before { |
|||
content: "["; |
|||
} |
|||
.markdown-body sup > a::after { |
|||
content: "]"; |
|||
} |
|||
.markdown-body h1 .octicon-link, |
|||
.markdown-body h2 .octicon-link, |
|||
.markdown-body h3 .octicon-link, |
|||
.markdown-body h4 .octicon-link, |
|||
.markdown-body h5 .octicon-link, |
|||
.markdown-body h6 .octicon-link { |
|||
color: var(--color-fg-default); |
|||
vertical-align: middle; |
|||
visibility: hidden; |
|||
} |
|||
.markdown-body h1:hover .anchor, |
|||
.markdown-body h2:hover .anchor, |
|||
.markdown-body h3:hover .anchor, |
|||
.markdown-body h4:hover .anchor, |
|||
.markdown-body h5:hover .anchor, |
|||
.markdown-body h6:hover .anchor { |
|||
text-decoration: none; |
|||
} |
|||
.markdown-body h1:hover .anchor .octicon-link, |
|||
.markdown-body h2:hover .anchor .octicon-link, |
|||
.markdown-body h3:hover .anchor .octicon-link, |
|||
.markdown-body h4:hover .anchor .octicon-link, |
|||
.markdown-body h5:hover .anchor .octicon-link, |
|||
.markdown-body h6:hover .anchor .octicon-link { |
|||
visibility: visible; |
|||
} |
|||
.markdown-body h1 code, |
|||
.markdown-body h1 tt, |
|||
.markdown-body h2 code, |
|||
.markdown-body h2 tt, |
|||
.markdown-body h3 code, |
|||
.markdown-body h3 tt, |
|||
.markdown-body h4 code, |
|||
.markdown-body h4 tt, |
|||
.markdown-body h5 code, |
|||
.markdown-body h5 tt, |
|||
.markdown-body h6 code, |
|||
.markdown-body h6 tt { |
|||
padding: 0 0.2em; |
|||
font-size: inherit; |
|||
} |
|||
.markdown-body ol.no-list, |
|||
.markdown-body ul.no-list { |
|||
padding: 0; |
|||
list-style-type: none; |
|||
} |
|||
.markdown-body ol[type="1"] { |
|||
list-style-type: decimal; |
|||
} |
|||
.markdown-body ol[type="a"] { |
|||
list-style-type: lower-alpha; |
|||
} |
|||
.markdown-body ol[type="i"] { |
|||
list-style-type: lower-roman; |
|||
} |
|||
.markdown-body div > ol:not([type]) { |
|||
list-style-type: decimal; |
|||
} |
|||
.markdown-body ol ol, |
|||
.markdown-body ol ul, |
|||
.markdown-body ul ol, |
|||
.markdown-body ul ul { |
|||
margin-top: 0; |
|||
margin-bottom: 0; |
|||
} |
|||
.markdown-body li > p { |
|||
margin-top: 16px; |
|||
} |
|||
.markdown-body li + li { |
|||
margin-top: 0.25em; |
|||
} |
|||
.markdown-body dl { |
|||
padding: 0; |
|||
} |
|||
.markdown-body dl dt { |
|||
padding: 0; |
|||
margin-top: 16px; |
|||
font-size: 1em; |
|||
font-style: italic; |
|||
font-weight: 600; |
|||
} |
|||
.markdown-body dl dd { |
|||
padding: 0 16px; |
|||
margin-bottom: 16px; |
|||
} |
|||
.markdown-body table th { |
|||
font-weight: 600; |
|||
} |
|||
.markdown-body table td, |
|||
.markdown-body table th { |
|||
padding: 6px 13px; |
|||
border: 1px solid var(--color-border-default); |
|||
} |
|||
.markdown-body table tr { |
|||
background-color: var(--color-canvas-default); |
|||
border-top: 1px solid var(--color-border-muted); |
|||
} |
|||
.markdown-body table tr:nth-child(2n) { |
|||
background-color: var(--color-canvas-subtle); |
|||
} |
|||
.markdown-body table img { |
|||
background-color: transparent; |
|||
} |
|||
.markdown-body img[align="right"] { |
|||
padding-left: 20px; |
|||
} |
|||
.markdown-body img[align="left"] { |
|||
padding-right: 20px; |
|||
} |
|||
.markdown-body .emoji { |
|||
max-width: none; |
|||
vertical-align: text-top; |
|||
background-color: transparent; |
|||
} |
|||
.markdown-body span.frame { |
|||
display: block; |
|||
overflow: hidden; |
|||
} |
|||
.markdown-body span.frame > span { |
|||
display: block; |
|||
float: left; |
|||
width: auto; |
|||
padding: 7px; |
|||
margin: 13px 0 0; |
|||
overflow: hidden; |
|||
border: 1px solid var(--color-border-default); |
|||
} |
|||
.markdown-body span.frame span img { |
|||
display: block; |
|||
float: left; |
|||
} |
|||
.markdown-body span.frame span span { |
|||
display: block; |
|||
padding: 5px 0 0; |
|||
clear: both; |
|||
color: var(--color-fg-default); |
|||
} |
|||
.markdown-body span.align-center { |
|||
display: block; |
|||
overflow: hidden; |
|||
clear: both; |
|||
} |
|||
.markdown-body span.align-center > span { |
|||
display: block; |
|||
margin: 13px auto 0; |
|||
overflow: hidden; |
|||
text-align: center; |
|||
} |
|||
.markdown-body span.align-center span img { |
|||
margin: 0 auto; |
|||
text-align: center; |
|||
} |
|||
.markdown-body span.align-right { |
|||
display: block; |
|||
overflow: hidden; |
|||
clear: both; |
|||
} |
|||
.markdown-body span.align-right > span { |
|||
display: block; |
|||
margin: 13px 0 0; |
|||
overflow: hidden; |
|||
text-align: right; |
|||
} |
|||
.markdown-body span.align-right span img { |
|||
margin: 0; |
|||
text-align: right; |
|||
} |
|||
.markdown-body span.float-left { |
|||
display: block; |
|||
float: left; |
|||
margin-right: 13px; |
|||
overflow: hidden; |
|||
} |
|||
.markdown-body span.float-left span { |
|||
margin: 13px 0 0; |
|||
} |
|||
.markdown-body span.float-right { |
|||
display: block; |
|||
float: right; |
|||
margin-left: 13px; |
|||
overflow: hidden; |
|||
} |
|||
.markdown-body span.float-right > span { |
|||
display: block; |
|||
margin: 13px auto 0; |
|||
overflow: hidden; |
|||
text-align: right; |
|||
} |
|||
.markdown-body code, |
|||
.markdown-body tt { |
|||
padding: 0.2em 0.4em; |
|||
margin: 0; |
|||
font-size: 85%; |
|||
background-color: var(--color-neutral-muted); |
|||
border-radius: 6px; |
|||
} |
|||
.markdown-body code br, |
|||
.markdown-body tt br { |
|||
display: none; |
|||
} |
|||
.markdown-body del code { |
|||
text-decoration: inherit; |
|||
} |
|||
.markdown-body pre code { |
|||
font-size: 100%; |
|||
} |
|||
.markdown-body pre > code { |
|||
padding: 0; |
|||
margin: 0; |
|||
word-break: normal; |
|||
white-space: pre; |
|||
background: 0 0; |
|||
border: 0; |
|||
} |
|||
.markdown-body .highlight { |
|||
margin-bottom: 16px; |
|||
} |
|||
.markdown-body .highlight pre { |
|||
margin-bottom: 0; |
|||
word-break: normal; |
|||
} |
|||
.markdown-body .highlight pre, |
|||
.markdown-body pre { |
|||
padding: 16px; |
|||
overflow: auto; |
|||
font-size: 85%; |
|||
line-height: 1.45; |
|||
background-color: var(--color-canvas-subtle); |
|||
border-radius: 6px; |
|||
} |
|||
.markdown-body pre code, |
|||
.markdown-body pre tt { |
|||
display: inline; |
|||
max-width: auto; |
|||
padding: 0; |
|||
margin: 0; |
|||
overflow: visible; |
|||
line-height: inherit; |
|||
word-wrap: normal; |
|||
background-color: transparent; |
|||
border: 0; |
|||
} |
|||
.markdown-body .csv-data td, |
|||
.markdown-body .csv-data th { |
|||
padding: 5px; |
|||
overflow: hidden; |
|||
font-size: 12px; |
|||
line-height: 1; |
|||
text-align: left; |
|||
white-space: nowrap; |
|||
} |
|||
.markdown-body .csv-data .blob-num { |
|||
padding: 10px 8px 9px; |
|||
text-align: right; |
|||
background: var(--color-canvas-default); |
|||
border: 0; |
|||
} |
|||
.markdown-body .csv-data tr { |
|||
border-top: 0; |
|||
} |
|||
.markdown-body .csv-data th { |
|||
font-weight: 600; |
|||
background: var(--color-canvas-subtle); |
|||
border-top: 0; |
|||
} |
|||
.markdown-body .footnotes { |
|||
font-size: 12px; |
|||
color: var(--color-fg-muted); |
|||
border-top: 1px solid var(--color-border-default); |
|||
} |
|||
.markdown-body .footnotes ol { |
|||
padding-left: 16px; |
|||
} |
|||
.markdown-body .footnotes li { |
|||
position: relative; |
|||
} |
|||
.markdown-body .footnotes li:target::before { |
|||
position: absolute; |
|||
top: -8px; |
|||
right: -8px; |
|||
bottom: -8px; |
|||
left: -24px; |
|||
pointer-events: none; |
|||
content: ""; |
|||
border: 2px solid var(--color-accent-emphasis); |
|||
border-radius: 6px; |
|||
} |
|||
.markdown-body .footnotes li:target { |
|||
color: var(--color-fg-default); |
|||
} |
|||
.markdown-body .footnotes .data-footnote-backref g-emoji { |
|||
font-family: monospace; |
|||
} |
|||
.markdown-body .task-list-item { |
|||
list-style-type: none; |
|||
} |
|||
.markdown-body .task-list-item label { |
|||
font-weight: 400; |
|||
} |
|||
.markdown-body .task-list-item.enabled label { |
|||
cursor: pointer; |
|||
} |
|||
.markdown-body .task-list-item + .task-list-item { |
|||
margin-top: 3px; |
|||
} |
|||
.markdown-body .task-list-item .handle { |
|||
display: none; |
|||
} |
|||
.markdown-body .task-list-item-checkbox { |
|||
margin: 0 0.2em 0.25em -1.6em; |
|||
vertical-align: middle; |
|||
} |
|||
.markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox { |
|||
margin: 0 -1.6em 0.25em 0.2em; |
|||
} |
|||
.markdown-body ::-webkit-calendar-picker-indicator { |
|||
filter: invert(50%); |
|||
} |
|||
/*# sourceMappingURL=/sm/64d6754651b08011e56029ac6df83bb47c5a570dab69e24e289f71fd97eb927d.map */ |
@ -0,0 +1,111 @@ |
|||
/*! |
|||
Theme: Default |
|||
Description: Original highlight.js style |
|||
Author: (c) Ivan Sagalaev <maniac@softwaremaniacs.org> |
|||
Maintainer: @highlightjs/core-team |
|||
Website: https://highlightjs.org/ |
|||
License: see project LICENSE |
|||
Touched: 2021 |
|||
*/ |
|||
pre code.hljs { |
|||
display: block; |
|||
overflow-x: auto; |
|||
padding: 1em; |
|||
} |
|||
code.hljs { |
|||
padding: 3px 5px; |
|||
} |
|||
|
|||
.hljs { |
|||
--color: #444; |
|||
--background: #f3f3f3; |
|||
--comment: #697070; |
|||
--tag: #444a; |
|||
--tag-attr: #444; |
|||
--type: #800; |
|||
--title: #800; |
|||
--link: #ab5656; |
|||
--literal: #695; |
|||
--code: #397300; |
|||
--meta: #1f7199; |
|||
--meta-string: #38a; |
|||
} |
|||
|
|||
body.dark .hljs { |
|||
--color: var(--dark-text-color); |
|||
--background: var(--dark-bg-color); |
|||
--keyword: #fff; |
|||
--comment: #979797; |
|||
--tag: #fff; |
|||
--type: #d88; |
|||
} |
|||
|
|||
.hljs { |
|||
background: var(--background); |
|||
color: var(--color); |
|||
} |
|||
.hljs-comment { |
|||
color: var(--comment); |
|||
} |
|||
.hljs-punctuation, |
|||
.hljs-tag { |
|||
color: var(--tag); |
|||
} |
|||
.hljs-tag .hljs-attr, |
|||
.hljs-tag .hljs-name { |
|||
color: var(--tag-attr); |
|||
} |
|||
.hljs-attribute, |
|||
.hljs-doctag, |
|||
.hljs-keyword, |
|||
.hljs-meta .hljs-keyword, |
|||
.hljs-name, |
|||
.hljs-selector-tag { |
|||
font-weight: 700; |
|||
} |
|||
.hljs-deletion, |
|||
.hljs-number, |
|||
.hljs-quote, |
|||
.hljs-selector-class, |
|||
.hljs-selector-id, |
|||
.hljs-string, |
|||
.hljs-template-tag, |
|||
.hljs-type { |
|||
color: var(--type); |
|||
} |
|||
.hljs-section, |
|||
.hljs-title { |
|||
color: var(--title); |
|||
font-weight: 700; |
|||
} |
|||
.hljs-link, |
|||
.hljs-operator, |
|||
.hljs-regexp, |
|||
.hljs-selector-attr, |
|||
.hljs-selector-pseudo, |
|||
.hljs-symbol, |
|||
.hljs-template-variable, |
|||
.hljs-variable { |
|||
color: var(--link); |
|||
} |
|||
.hljs-literal { |
|||
color: var(--literal); |
|||
} |
|||
.hljs-addition, |
|||
.hljs-built_in, |
|||
.hljs-bullet, |
|||
.hljs-code { |
|||
color: var(--code); |
|||
} |
|||
.hljs-meta { |
|||
color: var(--meta); |
|||
} |
|||
.hljs-meta .hljs-string { |
|||
color: var(--meta-string); |
|||
} |
|||
.hljs-emphasis { |
|||
font-style: italic; |
|||
} |
|||
.hljs-strong { |
|||
font-weight: 700; |
|||
} |
@ -0,0 +1,2 @@ |
|||
function e(e){this.message=e}e.prototype=new Error,e.prototype.name="InvalidCharacterError";var r="undefined"!=typeof window&&window.atob&&window.atob.bind(window)||function(r){var t=String(r).replace(/=+$/,"");if(t.length%4==1)throw new e("'atob' failed: The string to be decoded is not correctly encoded.");for(var n,o,a=0,i=0,c="";o=t.charAt(i++);~o&&(n=a%4?64*n+o:o,a++%4)?c+=String.fromCharCode(255&n>>(-2*a&6)):0)o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(o);return c};function t(e){var t=e.replace(/-/g,"+").replace(/_/g,"/");switch(t.length%4){case 0:break;case 2:t+="==";break;case 3:t+="=";break;default:throw"Illegal base64url string!"}try{return function(e){return decodeURIComponent(r(e).replace(/(.)/g,(function(e,r){var t=r.charCodeAt(0).toString(16).toUpperCase();return t.length<2&&(t="0"+t),"%"+t})))}(t)}catch(e){return r(t)}}function n(e){this.message=e}function o(e,r){if("string"!=typeof e)throw new n("Invalid token specified");var o=!0===(r=r||{}).header?0:1;try{return JSON.parse(t(e.split(".")[o]))}catch(e){throw new n("Invalid token specified: "+e.message)}}n.prototype=new Error,n.prototype.name="InvalidTokenError";export default o;export{n as InvalidTokenError}; |
|||
//# sourceMappingURL=jwt-decode.esm.js.map
|
@ -0,0 +1,74 @@ |
|||
/* Make clicks pass-through */ |
|||
#nprogress { |
|||
pointer-events: none; |
|||
} |
|||
|
|||
#nprogress .bar { |
|||
background: #29d; |
|||
|
|||
position: fixed; |
|||
z-index: 1031; |
|||
top: 0; |
|||
left: 0; |
|||
|
|||
width: 100%; |
|||
height: 2px; |
|||
} |
|||
|
|||
/* Fancy blur effect */ |
|||
#nprogress .peg { |
|||
display: block; |
|||
position: absolute; |
|||
right: 0px; |
|||
width: 100px; |
|||
height: 100%; |
|||
box-shadow: 0 0 10px #29d, 0 0 5px #29d; |
|||
opacity: 1.0; |
|||
|
|||
-webkit-transform: rotate(3deg) translate(0px, -4px); |
|||
-ms-transform: rotate(3deg) translate(0px, -4px); |
|||
transform: rotate(3deg) translate(0px, -4px); |
|||
} |
|||
|
|||
/* Remove these to get rid of the spinner */ |
|||
#nprogress .spinner { |
|||
display: block; |
|||
position: fixed; |
|||
z-index: 1031; |
|||
top: 15px; |
|||
right: 15px; |
|||
} |
|||
|
|||
#nprogress .spinner-icon { |
|||
width: 18px; |
|||
height: 18px; |
|||
box-sizing: border-box; |
|||
|
|||
border: solid 2px transparent; |
|||
border-top-color: #29d; |
|||
border-left-color: #29d; |
|||
border-radius: 50%; |
|||
|
|||
-webkit-animation: nprogress-spinner 400ms linear infinite; |
|||
animation: nprogress-spinner 400ms linear infinite; |
|||
} |
|||
|
|||
.nprogress-custom-parent { |
|||
overflow: hidden; |
|||
position: relative; |
|||
} |
|||
|
|||
.nprogress-custom-parent #nprogress .spinner, |
|||
.nprogress-custom-parent #nprogress .bar { |
|||
position: absolute; |
|||
} |
|||
|
|||
@-webkit-keyframes nprogress-spinner { |
|||
0% { -webkit-transform: rotate(0deg); } |
|||
100% { -webkit-transform: rotate(360deg); } |
|||
} |
|||
@keyframes nprogress-spinner { |
|||
0% { transform: rotate(0deg); } |
|||
100% { transform: rotate(360deg); } |
|||
} |
|||
|
@ -0,0 +1,288 @@ |
|||
const __commonJS = (cb, mod) => function __require() { |
|||
return mod || (0, cb[Object.getOwnPropertyNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; |
|||
}; |
|||
|
|||
// node_modules/nprogress/nprogress.js
|
|||
var require_nprogress = __commonJS({ |
|||
"node_modules/nprogress/nprogress.js"(exports, module) { |
|||
(function (root, factory) { |
|||
if (typeof define === "function" && define.amd) { |
|||
define(factory); |
|||
} else if (typeof exports === "object") { |
|||
module.exports = factory(); |
|||
} else { |
|||
root.NProgress = factory(); |
|||
} |
|||
})(exports, function () { |
|||
var NProgress = {}; |
|||
NProgress.version = "0.2.0"; |
|||
var Settings = NProgress.settings = { |
|||
minimum: 0.08, |
|||
easing: "ease", |
|||
positionUsing: "", |
|||
speed: 200, |
|||
trickle: true, |
|||
trickleRate: 0.02, |
|||
trickleSpeed: 800, |
|||
showSpinner: true, |
|||
barSelector: '[role="bar"]', |
|||
spinnerSelector: '[role="spinner"]', |
|||
parent: "body", |
|||
template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>' |
|||
}; |
|||
NProgress.configure = function (options) { |
|||
var key, value; |
|||
for (key in options) { |
|||
value = options[key]; |
|||
if (value !== void 0 && options.hasOwnProperty(key)) |
|||
Settings[key] = value; |
|||
} |
|||
return this; |
|||
}; |
|||
NProgress.status = null; |
|||
NProgress.set = function (n) { |
|||
var started = NProgress.isStarted(); |
|||
n = clamp(n, Settings.minimum, 1); |
|||
NProgress.status = n === 1 ? null : n; |
|||
var progress = NProgress.render(!started), bar = progress.querySelector(Settings.barSelector), speed = Settings.speed, ease = Settings.easing; |
|||
progress.offsetWidth; |
|||
queue(function (next) { |
|||
if (Settings.positionUsing === "") |
|||
Settings.positionUsing = NProgress.getPositioningCSS(); |
|||
css(bar, barPositionCSS(n, speed, ease)); |
|||
if (n === 1) { |
|||
css(progress, { |
|||
transition: "none", |
|||
opacity: 1 |
|||
}); |
|||
progress.offsetWidth; |
|||
setTimeout(function () { |
|||
css(progress, { |
|||
transition: "all " + speed + "ms linear", |
|||
opacity: 0 |
|||
}); |
|||
setTimeout(function () { |
|||
NProgress.remove(); |
|||
next(); |
|||
}, speed); |
|||
}, speed); |
|||
} else { |
|||
setTimeout(next, speed); |
|||
} |
|||
}); |
|||
return this; |
|||
}; |
|||
NProgress.isStarted = function () { |
|||
return typeof NProgress.status === "number"; |
|||
}; |
|||
NProgress.start = function () { |
|||
if (!NProgress.status) |
|||
NProgress.set(0); |
|||
var work = function () { |
|||
setTimeout(function () { |
|||
if (!NProgress.status) |
|||
return; |
|||
NProgress.trickle(); |
|||
work(); |
|||
}, Settings.trickleSpeed); |
|||
}; |
|||
if (Settings.trickle) |
|||
work(); |
|||
return this; |
|||
}; |
|||
NProgress.done = function (force) { |
|||
if (!force && !NProgress.status) |
|||
return this; |
|||
return NProgress.inc(0.3 + 0.5 * Math.random()).set(1); |
|||
}; |
|||
NProgress.inc = function (amount) { |
|||
var n = NProgress.status; |
|||
if (!n) { |
|||
return NProgress.start(); |
|||
} else { |
|||
if (typeof amount !== "number") { |
|||
amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95); |
|||
} |
|||
n = clamp(n + amount, 0, 0.994); |
|||
return NProgress.set(n); |
|||
} |
|||
}; |
|||
NProgress.trickle = function () { |
|||
return NProgress.inc(Math.random() * Settings.trickleRate); |
|||
}; |
|||
(function () { |
|||
var initial = 0, current = 0; |
|||
NProgress.promise = function ($promise) { |
|||
if (!$promise || $promise.state() === "resolved") { |
|||
return this; |
|||
} |
|||
if (current === 0) { |
|||
NProgress.start(); |
|||
} |
|||
initial++; |
|||
current++; |
|||
$promise.always(function () { |
|||
current--; |
|||
if (current === 0) { |
|||
initial = 0; |
|||
NProgress.done(); |
|||
} else { |
|||
NProgress.set((initial - current) / initial); |
|||
} |
|||
}); |
|||
return this; |
|||
}; |
|||
})(); |
|||
NProgress.render = function (fromStart) { |
|||
if (NProgress.isRendered()) |
|||
return document.getElementById("nprogress"); |
|||
addClass(document.documentElement, "nprogress-busy"); |
|||
var progress = document.createElement("div"); |
|||
progress.id = "nprogress"; |
|||
progress.innerHTML = Settings.template; |
|||
var bar = progress.querySelector(Settings.barSelector), perc = fromStart ? "-100" : toBarPerc(NProgress.status || 0), parent = document.querySelector(Settings.parent), spinner; |
|||
css(bar, { |
|||
transition: "all 0 linear", |
|||
transform: "translate3d(" + perc + "%,0,0)" |
|||
}); |
|||
if (!Settings.showSpinner) { |
|||
spinner = progress.querySelector(Settings.spinnerSelector); |
|||
spinner && removeElement(spinner); |
|||
} |
|||
if (parent != document.body) { |
|||
addClass(parent, "nprogress-custom-parent"); |
|||
} |
|||
parent.appendChild(progress); |
|||
return progress; |
|||
}; |
|||
NProgress.remove = function () { |
|||
removeClass(document.documentElement, "nprogress-busy"); |
|||
removeClass(document.querySelector(Settings.parent), "nprogress-custom-parent"); |
|||
var progress = document.getElementById("nprogress"); |
|||
progress && removeElement(progress); |
|||
}; |
|||
NProgress.isRendered = function () { |
|||
return !!document.getElementById("nprogress"); |
|||
}; |
|||
NProgress.getPositioningCSS = function () { |
|||
var bodyStyle = document.body.style; |
|||
var vendorPrefix = "WebkitTransform" in bodyStyle ? "Webkit" : "MozTransform" in bodyStyle ? "Moz" : "msTransform" in bodyStyle ? "ms" : "OTransform" in bodyStyle ? "O" : ""; |
|||
if (vendorPrefix + "Perspective" in bodyStyle) { |
|||
return "translate3d"; |
|||
} else if (vendorPrefix + "Transform" in bodyStyle) { |
|||
return "translate"; |
|||
} else { |
|||
return "margin"; |
|||
} |
|||
}; |
|||
function clamp(n, min, max) { |
|||
if (n < min) |
|||
return min; |
|||
if (n > max) |
|||
return max; |
|||
return n; |
|||
} |
|||
function toBarPerc(n) { |
|||
return (-1 + n) * 100; |
|||
} |
|||
function barPositionCSS(n, speed, ease) { |
|||
var barCSS; |
|||
if (Settings.positionUsing === "translate3d") { |
|||
barCSS = { transform: "translate3d(" + toBarPerc(n) + "%,0,0)" }; |
|||
} else if (Settings.positionUsing === "translate") { |
|||
barCSS = { transform: "translate(" + toBarPerc(n) + "%,0)" }; |
|||
} else { |
|||
barCSS = { "margin-left": toBarPerc(n) + "%" }; |
|||
} |
|||
barCSS.transition = "all " + speed + "ms " + ease; |
|||
return barCSS; |
|||
} |
|||
var queue = function () { |
|||
var pending = []; |
|||
function next() { |
|||
var fn = pending.shift(); |
|||
if (fn) { |
|||
fn(next); |
|||
} |
|||
} |
|||
return function (fn) { |
|||
pending.push(fn); |
|||
if (pending.length == 1) |
|||
next(); |
|||
}; |
|||
}(); |
|||
var css = function () { |
|||
var cssPrefixes = ["Webkit", "O", "Moz", "ms"], cssProps = {}; |
|||
function camelCase(string) { |
|||
return string.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (match, letter) { |
|||
return letter.toUpperCase(); |
|||
}); |
|||
} |
|||
function getVendorProp(name) { |
|||
var style = document.body.style; |
|||
if (name in style) |
|||
return name; |
|||
var i = cssPrefixes.length, capName = name.charAt(0).toUpperCase() + name.slice(1), vendorName; |
|||
while (i--) { |
|||
vendorName = cssPrefixes[i] + capName; |
|||
if (vendorName in style) |
|||
return vendorName; |
|||
} |
|||
return name; |
|||
} |
|||
function getStyleProp(name) { |
|||
name = camelCase(name); |
|||
return cssProps[name] || (cssProps[name] = getVendorProp(name)); |
|||
} |
|||
function applyCss(element, prop, value) { |
|||
prop = getStyleProp(prop); |
|||
element.style[prop] = value; |
|||
} |
|||
return function (element, properties) { |
|||
var args = arguments, prop, value; |
|||
if (args.length == 2) { |
|||
for (prop in properties) { |
|||
value = properties[prop]; |
|||
if (value !== void 0 && properties.hasOwnProperty(prop)) |
|||
applyCss(element, prop, value); |
|||
} |
|||
} else { |
|||
applyCss(element, args[1], args[2]); |
|||
} |
|||
}; |
|||
}(); |
|||
function hasClass(element, name) { |
|||
var list = typeof element == "string" ? element : classList(element); |
|||
return list.indexOf(" " + name + " ") >= 0; |
|||
} |
|||
function addClass(element, name) { |
|||
var oldList = classList(element), newList = oldList + name; |
|||
if (hasClass(oldList, name)) |
|||
return; |
|||
element.className = newList.substring(1); |
|||
} |
|||
function removeClass(element, name) { |
|||
var oldList = classList(element), newList; |
|||
if (!hasClass(element, name)) |
|||
return; |
|||
newList = oldList.replace(" " + name + " ", " "); |
|||
element.className = newList.substring(1, newList.length - 1); |
|||
} |
|||
function classList(element) { |
|||
return (" " + (element.className || "") + " ").replace(/\s+/gi, " "); |
|||
} |
|||
function removeElement(element) { |
|||
element && element.parentNode && element.parentNode.removeChild(element); |
|||
} |
|||
return NProgress; |
|||
}); |
|||
} |
|||
}); |
|||
export default require_nprogress(); |
|||
/*! Bundled license information: |
|||
|
|||
nprogress/nprogress.js: |
|||
(* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
|
|||
* @license MIT *) |
|||
*/ |
|||
|
@ -0,0 +1,206 @@ |
|||
const __commonJS = (cb, mod) => function __require() { |
|||
return mod || (0, cb[Object.getOwnPropertyNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; |
|||
}; |
|||
|
|||
// node_modules/pubsub-js/src/pubsub.js
|
|||
var require_pubsub = __commonJS({ |
|||
"node_modules/pubsub-js/src/pubsub.js"(exports, module) { |
|||
(function(root, factory) { |
|||
"use strict"; |
|||
var PubSub = {}; |
|||
if (root.PubSub) { |
|||
PubSub = root.PubSub; |
|||
console.warn("PubSub already loaded, using existing version"); |
|||
} else { |
|||
root.PubSub = PubSub; |
|||
factory(PubSub); |
|||
} |
|||
if (typeof exports === "object") { |
|||
if (module !== void 0 && module.exports) { |
|||
exports = module.exports = PubSub; |
|||
} |
|||
exports.PubSub = PubSub; |
|||
module.exports = exports = PubSub; |
|||
} else if (typeof define === "function" && define.amd) { |
|||
define(function() { |
|||
return PubSub; |
|||
}); |
|||
} |
|||
})(typeof window === "object" && window || exports, function(PubSub) { |
|||
"use strict"; |
|||
var messages = {}, lastUid = -1, ALL_SUBSCRIBING_MSG = "*"; |
|||
function hasKeys(obj) { |
|||
var key; |
|||
for (key in obj) { |
|||
if (Object.prototype.hasOwnProperty.call(obj, key)) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
function throwException(ex) { |
|||
return function reThrowException() { |
|||
throw ex; |
|||
}; |
|||
} |
|||
function callSubscriberWithDelayedExceptions(subscriber, message, data) { |
|||
try { |
|||
subscriber(message, data); |
|||
} catch (ex) { |
|||
setTimeout(throwException(ex), 0); |
|||
} |
|||
} |
|||
function callSubscriberWithImmediateExceptions(subscriber, message, data) { |
|||
subscriber(message, data); |
|||
} |
|||
function deliverMessage(originalMessage, matchedMessage, data, immediateExceptions) { |
|||
var subscribers = messages[matchedMessage], callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions, s; |
|||
if (!Object.prototype.hasOwnProperty.call(messages, matchedMessage)) { |
|||
return; |
|||
} |
|||
for (s in subscribers) { |
|||
if (Object.prototype.hasOwnProperty.call(subscribers, s)) { |
|||
callSubscriber(subscribers[s], originalMessage, data); |
|||
} |
|||
} |
|||
} |
|||
function createDeliveryFunction(message, data, immediateExceptions) { |
|||
return function deliverNamespaced() { |
|||
var topic = String(message), position = topic.lastIndexOf("."); |
|||
deliverMessage(message, message, data, immediateExceptions); |
|||
while (position !== -1) { |
|||
topic = topic.substr(0, position); |
|||
position = topic.lastIndexOf("."); |
|||
deliverMessage(message, topic, data, immediateExceptions); |
|||
} |
|||
deliverMessage(message, ALL_SUBSCRIBING_MSG, data, immediateExceptions); |
|||
}; |
|||
} |
|||
function hasDirectSubscribersFor(message) { |
|||
var topic = String(message), found = Boolean(Object.prototype.hasOwnProperty.call(messages, topic) && hasKeys(messages[topic])); |
|||
return found; |
|||
} |
|||
function messageHasSubscribers(message) { |
|||
var topic = String(message), found = hasDirectSubscribersFor(topic) || hasDirectSubscribersFor(ALL_SUBSCRIBING_MSG), position = topic.lastIndexOf("."); |
|||
while (!found && position !== -1) { |
|||
topic = topic.substr(0, position); |
|||
position = topic.lastIndexOf("."); |
|||
found = hasDirectSubscribersFor(topic); |
|||
} |
|||
return found; |
|||
} |
|||
function publish(message, data, sync, immediateExceptions) { |
|||
message = typeof message === "symbol" ? message.toString() : message; |
|||
var deliver = createDeliveryFunction(message, data, immediateExceptions), hasSubscribers = messageHasSubscribers(message); |
|||
if (!hasSubscribers) { |
|||
return false; |
|||
} |
|||
if (sync === true) { |
|||
deliver(); |
|||
} else { |
|||
setTimeout(deliver, 0); |
|||
} |
|||
return true; |
|||
} |
|||
PubSub.publish = function(message, data) { |
|||
return publish(message, data, false, PubSub.immediateExceptions); |
|||
}; |
|||
PubSub.publishSync = function(message, data) { |
|||
return publish(message, data, true, PubSub.immediateExceptions); |
|||
}; |
|||
PubSub.subscribe = function(message, func) { |
|||
if (typeof func !== "function") { |
|||
return false; |
|||
} |
|||
message = typeof message === "symbol" ? message.toString() : message; |
|||
if (!Object.prototype.hasOwnProperty.call(messages, message)) { |
|||
messages[message] = {}; |
|||
} |
|||
var token = "uid_" + String(++lastUid); |
|||
messages[message][token] = func; |
|||
return token; |
|||
}; |
|||
PubSub.subscribeAll = function(func) { |
|||
return PubSub.subscribe(ALL_SUBSCRIBING_MSG, func); |
|||
}; |
|||
PubSub.subscribeOnce = function(message, func) { |
|||
var token = PubSub.subscribe(message, function() { |
|||
PubSub.unsubscribe(token); |
|||
func.apply(this, arguments); |
|||
}); |
|||
return PubSub; |
|||
}; |
|||
PubSub.clearAllSubscriptions = function clearAllSubscriptions() { |
|||
messages = {}; |
|||
}; |
|||
PubSub.clearSubscriptions = function clearSubscriptions(topic) { |
|||
var m; |
|||
for (m in messages) { |
|||
if (Object.prototype.hasOwnProperty.call(messages, m) && m.indexOf(topic) === 0) { |
|||
delete messages[m]; |
|||
} |
|||
} |
|||
}; |
|||
PubSub.countSubscriptions = function countSubscriptions(topic) { |
|||
var m; |
|||
var token; |
|||
var count = 0; |
|||
for (m in messages) { |
|||
if (Object.prototype.hasOwnProperty.call(messages, m) && m.indexOf(topic) === 0) { |
|||
for (token in messages[m]) { |
|||
count++; |
|||
} |
|||
break; |
|||
} |
|||
} |
|||
return count; |
|||
}; |
|||
PubSub.getSubscriptions = function getSubscriptions(topic) { |
|||
var m; |
|||
var list = []; |
|||
for (m in messages) { |
|||
if (Object.prototype.hasOwnProperty.call(messages, m) && m.indexOf(topic) === 0) { |
|||
list.push(m); |
|||
} |
|||
} |
|||
return list; |
|||
}; |
|||
PubSub.unsubscribe = function(value) { |
|||
var descendantTopicExists = function(topic) { |
|||
var m2; |
|||
for (m2 in messages) { |
|||
if (Object.prototype.hasOwnProperty.call(messages, m2) && m2.indexOf(topic) === 0) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
}, isTopic = typeof value === "string" && (Object.prototype.hasOwnProperty.call(messages, value) || descendantTopicExists(value)), isToken = !isTopic && typeof value === "string", isFunction = typeof value === "function", result = false, m, message, t; |
|||
if (isTopic) { |
|||
PubSub.clearSubscriptions(value); |
|||
return; |
|||
} |
|||
for (m in messages) { |
|||
if (Object.prototype.hasOwnProperty.call(messages, m)) { |
|||
message = messages[m]; |
|||
if (isToken && message[value]) { |
|||
delete message[value]; |
|||
result = value; |
|||
break; |
|||
} |
|||
if (isFunction) { |
|||
for (t in message) { |
|||
if (Object.prototype.hasOwnProperty.call(message, t) && message[t] === value) { |
|||
delete message[t]; |
|||
result = true; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return result; |
|||
}; |
|||
}); |
|||
} |
|||
}); |
|||
export default require_pubsub(); |
|||
|
@ -0,0 +1,314 @@ |
|||
var raf = null; |
|||
function requestAnimationFrame (callback) { |
|||
if (!raf) { |
|||
raf = ( |
|||
window.requestAnimationFrame || |
|||
window.webkitRequestAnimationFrame || |
|||
window.mozRequestAnimationFrame || |
|||
function (callback) { |
|||
return setTimeout(callback, 16) |
|||
} |
|||
).bind(window); |
|||
} |
|||
return raf(callback) |
|||
} |
|||
|
|||
var caf = null; |
|||
function cancelAnimationFrame (id) { |
|||
if (!caf) { |
|||
caf = ( |
|||
window.cancelAnimationFrame || |
|||
window.webkitCancelAnimationFrame || |
|||
window.mozCancelAnimationFrame || |
|||
function (id) { |
|||
clearTimeout(id); |
|||
} |
|||
).bind(window); |
|||
} |
|||
|
|||
caf(id); |
|||
} |
|||
|
|||
function createStyles (styleText) { |
|||
var style = document.createElement('style'); |
|||
|
|||
if (style.styleSheet) { |
|||
style.styleSheet.cssText = styleText; |
|||
} else { |
|||
style.appendChild(document.createTextNode(styleText)); |
|||
} |
|||
(document.querySelector('head') || document.body).appendChild(style); |
|||
return style |
|||
} |
|||
|
|||
function createElement (tagName, props) { |
|||
if ( props === void 0 ) props = {}; |
|||
|
|||
var elem = document.createElement(tagName); |
|||
Object.keys(props).forEach(function (key) { |
|||
elem[key] = props[key]; |
|||
}); |
|||
return elem |
|||
} |
|||
|
|||
function getComputedStyle (elem, prop, pseudo) { |
|||
// for older versions of Firefox, `getComputedStyle` required
|
|||
// the second argument and may return `null` for some elements
|
|||
// when `display: none`
|
|||
var computedStyle = window.getComputedStyle(elem, pseudo || null) || { |
|||
display: 'none' |
|||
}; |
|||
|
|||
return computedStyle[prop] |
|||
} |
|||
|
|||
function getRenderInfo (elem) { |
|||
if (!document.documentElement.contains(elem)) { |
|||
return { |
|||
detached: true, |
|||
rendered: false |
|||
} |
|||
} |
|||
|
|||
var current = elem; |
|||
while (current !== document) { |
|||
if (getComputedStyle(current, 'display') === 'none') { |
|||
return { |
|||
detached: false, |
|||
rendered: false |
|||
} |
|||
} |
|||
current = current.parentNode; |
|||
} |
|||
|
|||
return { |
|||
detached: false, |
|||
rendered: true |
|||
} |
|||
} |
|||
|
|||
var css_248z = ".resize-triggers{visibility:hidden;opacity:0;pointer-events:none}.resize-contract-trigger,.resize-contract-trigger:before,.resize-expand-trigger,.resize-triggers{content:\"\";position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden}.resize-contract-trigger,.resize-expand-trigger{background:#eee;overflow:auto}.resize-contract-trigger:before{width:200%;height:200%}"; |
|||
|
|||
var total = 0; |
|||
var style = null; |
|||
|
|||
function addListener (elem, callback) { |
|||
if (!elem.__resize_mutation_handler__) { |
|||
elem.__resize_mutation_handler__ = handleMutation.bind(elem); |
|||
} |
|||
|
|||
var listeners = elem.__resize_listeners__; |
|||
|
|||
if (!listeners) { |
|||
elem.__resize_listeners__ = []; |
|||
if (window.ResizeObserver) { |
|||
var offsetWidth = elem.offsetWidth; |
|||
var offsetHeight = elem.offsetHeight; |
|||
var ro = new ResizeObserver(function () { |
|||
if (!elem.__resize_observer_triggered__) { |
|||
elem.__resize_observer_triggered__ = true; |
|||
if (elem.offsetWidth === offsetWidth && elem.offsetHeight === offsetHeight) { |
|||
return |
|||
} |
|||
} |
|||
runCallbacks(elem); |
|||
}); |
|||
|
|||
// initially display none won't trigger ResizeObserver callback
|
|||
var ref = getRenderInfo(elem); |
|||
var detached = ref.detached; |
|||
var rendered = ref.rendered; |
|||
elem.__resize_observer_triggered__ = detached === false && rendered === false; |
|||
elem.__resize_observer__ = ro; |
|||
ro.observe(elem); |
|||
} else if (elem.attachEvent && elem.addEventListener) { |
|||
// targeting IE9/10
|
|||
elem.__resize_legacy_resize_handler__ = function handleLegacyResize () { |
|||
runCallbacks(elem); |
|||
}; |
|||
elem.attachEvent('onresize', elem.__resize_legacy_resize_handler__); |
|||
document.addEventListener('DOMSubtreeModified', elem.__resize_mutation_handler__); |
|||
} else { |
|||
if (!total) { |
|||
style = createStyles(css_248z); |
|||
} |
|||
initTriggers(elem); |
|||
|
|||
elem.__resize_rendered__ = getRenderInfo(elem).rendered; |
|||
if (window.MutationObserver) { |
|||
var mo = new MutationObserver(elem.__resize_mutation_handler__); |
|||
mo.observe(document, { |
|||
attributes: true, |
|||
childList: true, |
|||
characterData: true, |
|||
subtree: true |
|||
}); |
|||
elem.__resize_mutation_observer__ = mo; |
|||
} |
|||
} |
|||
} |
|||
|
|||
elem.__resize_listeners__.push(callback); |
|||
total++; |
|||
} |
|||
|
|||
function removeListener (elem, callback) { |
|||
var listeners = elem.__resize_listeners__; |
|||
if (!listeners) { |
|||
return |
|||
} |
|||
|
|||
if (callback) { |
|||
listeners.splice(listeners.indexOf(callback), 1); |
|||
} |
|||
|
|||
// no listeners exist, or removing all listeners
|
|||
if (!listeners.length || !callback) { |
|||
// targeting IE9/10
|
|||
if (elem.detachEvent && elem.removeEventListener) { |
|||
elem.detachEvent('onresize', elem.__resize_legacy_resize_handler__); |
|||
document.removeEventListener('DOMSubtreeModified', elem.__resize_mutation_handler__); |
|||
return |
|||
} |
|||
|
|||
if (elem.__resize_observer__) { |
|||
elem.__resize_observer__.unobserve(elem); |
|||
elem.__resize_observer__.disconnect(); |
|||
elem.__resize_observer__ = null; |
|||
} else { |
|||
if (elem.__resize_mutation_observer__) { |
|||
elem.__resize_mutation_observer__.disconnect(); |
|||
elem.__resize_mutation_observer__ = null; |
|||
} |
|||
elem.removeEventListener('scroll', handleScroll); |
|||
elem.removeChild(elem.__resize_triggers__.triggers); |
|||
elem.__resize_triggers__ = null; |
|||
} |
|||
elem.__resize_listeners__ = null; |
|||
} |
|||
|
|||
if (!--total && style) { |
|||
style.parentNode.removeChild(style); |
|||
} |
|||
} |
|||
|
|||
function getUpdatedSize (elem) { |
|||
var ref = elem.__resize_last__; |
|||
var width = ref.width; |
|||
var height = ref.height; |
|||
var offsetWidth = elem.offsetWidth; |
|||
var offsetHeight = elem.offsetHeight; |
|||
if (offsetWidth !== width || offsetHeight !== height) { |
|||
return { |
|||
width: offsetWidth, |
|||
height: offsetHeight |
|||
} |
|||
} |
|||
return null |
|||
} |
|||
|
|||
function handleMutation () { |
|||
// `this` denotes the scrolling element
|
|||
var ref = getRenderInfo(this); |
|||
var rendered = ref.rendered; |
|||
var detached = ref.detached; |
|||
if (rendered !== this.__resize_rendered__) { |
|||
if (!detached && this.__resize_triggers__) { |
|||
resetTriggers(this); |
|||
this.addEventListener('scroll', handleScroll, true); |
|||
} |
|||
this.__resize_rendered__ = rendered; |
|||
runCallbacks(this); |
|||
} |
|||
} |
|||
|
|||
function handleScroll () { |
|||
var this$1 = this; |
|||
|
|||
// `this` denotes the scrolling element
|
|||
resetTriggers(this); |
|||
if (this.__resize_raf__) { |
|||
cancelAnimationFrame(this.__resize_raf__); |
|||
} |
|||
this.__resize_raf__ = requestAnimationFrame(function () { |
|||
var updated = getUpdatedSize(this$1); |
|||
if (updated) { |
|||
this$1.__resize_last__ = updated; |
|||
runCallbacks(this$1); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
function runCallbacks (elem) { |
|||
if (!elem || !elem.__resize_listeners__) { |
|||
return |
|||
} |
|||
elem.__resize_listeners__.forEach(function (callback) { |
|||
callback.call(elem, elem); |
|||
}); |
|||
} |
|||
|
|||
function initTriggers (elem) { |
|||
var position = getComputedStyle(elem, 'position'); |
|||
if (!position || position === 'static') { |
|||
elem.style.position = 'relative'; |
|||
} |
|||
|
|||
elem.__resize_old_position__ = position; |
|||
elem.__resize_last__ = {}; |
|||
|
|||
var triggers = createElement('div', { |
|||
className: 'resize-triggers' |
|||
}); |
|||
var expand = createElement('div', { |
|||
className: 'resize-expand-trigger' |
|||
}); |
|||
var expandChild = createElement('div'); |
|||
var contract = createElement('div', { |
|||
className: 'resize-contract-trigger' |
|||
}); |
|||
expand.appendChild(expandChild); |
|||
triggers.appendChild(expand); |
|||
triggers.appendChild(contract); |
|||
elem.appendChild(triggers); |
|||
|
|||
elem.__resize_triggers__ = { |
|||
triggers: triggers, |
|||
expand: expand, |
|||
expandChild: expandChild, |
|||
contract: contract |
|||
}; |
|||
|
|||
resetTriggers(elem); |
|||
elem.addEventListener('scroll', handleScroll, true); |
|||
|
|||
elem.__resize_last__ = { |
|||
width: elem.offsetWidth, |
|||
height: elem.offsetHeight |
|||
}; |
|||
} |
|||
|
|||
function resetTriggers (elem) { |
|||
var ref = elem.__resize_triggers__; |
|||
var expand = ref.expand; |
|||
var expandChild = ref.expandChild; |
|||
var contract = ref.contract; |
|||
|
|||
// batch read
|
|||
var csw = contract.scrollWidth; |
|||
var csh = contract.scrollHeight; |
|||
var eow = expand.offsetWidth; |
|||
var eoh = expand.offsetHeight; |
|||
var esw = expand.scrollWidth; |
|||
var esh = expand.scrollHeight; |
|||
|
|||
// batch write
|
|||
contract.scrollLeft = csw; |
|||
contract.scrollTop = csh; |
|||
expandChild.style.width = eow + 1 + 'px'; |
|||
expandChild.style.height = eoh + 1 + 'px'; |
|||
expand.scrollLeft = esw; |
|||
expand.scrollTop = esh; |
|||
} |
|||
|
|||
export { addListener, removeListener }; |
@ -0,0 +1,34 @@ |
|||
import * as Vue from 'vue' |
|||
|
|||
var isVue2 = false |
|||
var isVue3 = true |
|||
var Vue2 = undefined |
|||
|
|||
function install() {} |
|||
|
|||
export function set(target, key, val) { |
|||
if (Array.isArray(target)) { |
|||
target.length = Math.max(target.length, key) |
|||
target.splice(key, 1, val) |
|||
return val |
|||
} |
|||
target[key] = val |
|||
return val |
|||
} |
|||
|
|||
export function del(target, key) { |
|||
if (Array.isArray(target)) { |
|||
target.splice(key, 1) |
|||
return |
|||
} |
|||
delete target[key] |
|||
} |
|||
|
|||
export * from 'vue' |
|||
export { |
|||
Vue, |
|||
Vue2, |
|||
isVue2, |
|||
isVue3, |
|||
install, |
|||
} |
@ -0,0 +1,2 @@ |
|||
import{watch as e,inject as t,computed as n,unref as o,watchEffect as r,defineComponent as i,shallowRef as a,toRefs as u,onMounted as c,onUnmounted as s,h as l,Vue2 as p,nextTick as v}from"vue-demi";import{throttle as f,init as d}from"echarts/core";import{addListener as g,removeListener as h}from"resize-detector";var O=function(){return(O=Object.assign||function(e){for(var t,n=1,o=arguments.length;n<o;n++)for(var r in t=arguments[n])Object.prototype.hasOwnProperty.call(t,r)&&(e[r]=t[r]);return e}).apply(this,arguments)},m=["getWidth","getHeight","getDom","getOption","resize","dispatchAction","convertToPixel","convertFromPixel","containPixel","getDataURL","getConnectedDataURL","appendData","clear","isDisposed","dispose"];function b(e){return t=Object.create(null),m.forEach((function(n){t[n]=function(t){return function(){for(var n=[],o=0;o<arguments.length;o++)n[o]=arguments[o];if(!e.value)throw new Error("ECharts is not initialized yet.");return e.value[t].apply(e.value,n)}}(n)})),t;var t}var y={autoresize:Boolean},x="ecLoadingOptions";var j={loading:Boolean,loadingOptions:Object},E=[],z=[];!function(e,t){if(e&&"undefined"!=typeof document){var n,o=!0===t.prepend?"prepend":"append",r=!0===t.singleTag,i="string"==typeof t.container?document.querySelector(t.container):document.getElementsByTagName("head")[0];if(r){var a=E.indexOf(i);-1===a&&(a=E.push(i)-1,z[a]={}),n=z[a]&&z[a][o]?z[a][o]:z[a][o]=u()}else n=u();65279===e.charCodeAt(0)&&(e=e.substring(1)),n.styleSheet?n.styleSheet.cssText+=e:n.appendChild(document.createTextNode(e))}function u(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),t.attributes)for(var n=Object.keys(t.attributes),r=0;r<n.length;r++)e.setAttribute(n[r],t.attributes[n[r]]);var a="prepend"===o?"afterbegin":"beforeend";return i.insertAdjacentElement(a,e),e}}("x-vue-echarts{display:block;width:100%;height:100%}",{});var A=/^on[^a-z]/,L=function(e){return A.test(e)};p&&p.config.ignoredElements.push("x-vue-echarts");var w="ecTheme",C="ecInitOptions",T="ecUpdateOptions",U=i({name:"echarts",props:O(O({option:Object,theme:{type:[Object,String]},initOptions:Object,updateOptions:Object,group:String,manualUpdate:Boolean},y),j),inheritAttrs:!1,setup:function(i,l){var p=l.attrs,m=l.listeners,y=a(),x=a(),j=a(),E=t("ecTheme",null),z=t("ecInitOptions",null),A=t("ecUpdateOptions",null),w=u(i),C=w.autoresize,T=w.manualUpdate,U=w.loading,D=w.loadingOptions,S=n((function(){return j.value||i.option||null})),k=n((function(){return i.theme||o(E)||{}})),B=n((function(){return i.initOptions||o(z)||{}})),P=n((function(){return i.updateOptions||o(A)||{}})),I=n((function(){return function(e){var t={};for(var n in e)L(n)||(t[n]=e[n]);return t}(p)}));function N(e){if(y.value){var t=x.value=d(y.value,k.value,B.value);i.group&&(t.group=i.group);var n=m;n||(n={},Object.keys(p).filter((function(e){return 0===e.indexOf("on")&&e.length>2})).forEach((function(e){var t=e.charAt(2).toLowerCase()+e.slice(3);n[t]=p[e]}))),Object.keys(n).forEach((function(e){var o=n[e];o&&(0===e.indexOf("zr:")?t.getZr().on(e.slice(3).toLowerCase(),o):t.on(e.toLowerCase(),o))})),C.value?v((function(){t&&!t.isDisposed()&&t.resize(),o()})):o()}function o(){var n=e||S.value;n&&t.setOption(n,P.value)}}function R(){x.value&&(x.value.dispose(),x.value=void 0)}var q=null;e(T,(function(t){"function"==typeof q&&(q(),q=null),t||(q=e((function(){return i.option}),(function(e,t){e&&(x.value?x.value.setOption(e,O({notMerge:e.value!==(null==t?void 0:t.value)},P.value)):N())}),{deep:!0}))}),{immediate:!0}),e([k,B],(function(){R(),N()}),{deep:!0}),r((function(){i.group&&x.value&&(x.value.group=i.group)}));var F=b(x);return function(e,i,a){var u=t("ecLoadingOptions",{}),c=n((function(){return O(O({},o(u)),null==a?void 0:a.value)}));r((function(){var t=e.value;t&&(i.value?t.showLoading(c.value):t.hideLoading())}))}(x,U,D),function(t,n,o){var r=null;e([o,t,n],(function(e,t,n){var o=e[0],i=e[1],a=e[2];o&&i&&a&&(r=f((function(){i.resize()}),100),g(o,r)),n((function(){r&&o&&h(o,r)}))}))}(x,C,y),c((function(){N()})),s(R),O({chart:x,root:y,setOption:function(e,t){i.manualUpdate&&(j.value=e),x.value?x.value.setOption(e,t||{}):N(e)},nonEventAttrs:I},F)},render:function(){var e=O({},this.nonEventAttrs);return e.ref="root",e.class=e.class?["echarts"].concat(e.class):"echarts",l("x-vue-echarts",e)}});export default U;export{C as INIT_OPTIONS_KEY,x as LOADING_OPTIONS_KEY,w as THEME_KEY,T as UPDATE_OPTIONS_KEY}; |
|||
//# sourceMappingURL=index.esm.min.js.map
|
@ -0,0 +1,13 @@ |
|||
import { createI18n } from "vue-i18n"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
|
|||
function useLocale() { |
|||
const appStore = useAppStore(); |
|||
const i18n = createI18n({ |
|||
legacy: false, |
|||
...appStore.localization, |
|||
}); |
|||
return i18n; |
|||
} |
|||
|
|||
export default useLocale; |
@ -0,0 +1,8 @@ |
|||
@import url("./lib/nprogress/nprogress.css"); |
|||
@import url("./lib/element-plus/index.css"); |
|||
@import url("./lib/element-plus/theme-chalk/dark/css-vars.css"); |
|||
@import url("./lib/github-markdown-css/github-markdown.min.css"); |
|||
@import url("./lib/highlightjs/highlight.css"); |
|||
@import url("./lib/@vue-office/excel/index.css"); |
|||
@import url("./lib/tailwindcss/tailwind.min.css"); |
|||
@import url("./styles/site.css"); |
@ -0,0 +1,20 @@ |
|||
import { createApp } from "vue"; |
|||
import style from './mixins/style.js'; |
|||
import store, { useAppStore } from "./store/index.js"; |
|||
import router from "./router/index.js"; |
|||
import ElementPlus from "element-plus"; |
|||
import * as ElementPlusIconsVue from "@element-plus/icons-vue"; |
|||
import App from "/app.js"; |
|||
import useLocale from "./locale/index.js"; |
|||
|
|||
const app = createApp(App); |
|||
app.use(store); |
|||
await useAppStore().init(); |
|||
app.use(useLocale()); |
|||
app.use(router); |
|||
app.use(ElementPlus); |
|||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
|||
app.component(`Ep${key}`, component); |
|||
} |
|||
app.mixin(style); |
|||
app.mount("#app"); |
@ -0,0 +1,60 @@ |
|||
const styleCounterName = 'data-vue-component-instances'; |
|||
|
|||
function getStyleList(name) { |
|||
return document.querySelectorAll(`head style.${name},head link[rel='stylesheet'].${name}`); |
|||
} |
|||
|
|||
function append(parent, html) { |
|||
parent.insertAdjacentHTML('beforeend', html); |
|||
} |
|||
|
|||
function addStyles(name, styleSource) { |
|||
var styleList = getStyleList(name); |
|||
if (styleList.length > 0) { |
|||
for (let i = 0; i < styleList.length; i++) { |
|||
const style = styleList[i]; |
|||
var counter = parseInt(style.getAttribute(styleCounterName)); |
|||
style.setAttribute(styleCounterName, counter + 1); |
|||
} |
|||
} else { |
|||
const doc = new DOMParser().parseFromString(styleSource, 'text/html'); |
|||
const styles = doc.querySelectorAll("style,link[rel='stylesheet']"); |
|||
for (let i = 0; i < styles.length; i++) { |
|||
const style = styles[i]; |
|||
style.setAttribute('class', name); |
|||
style.setAttribute(styleCounterName, 1); |
|||
append(document.head, style.outerHTML); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function removeStyles(name) { |
|||
var styleList = getStyleList(name); |
|||
if (styleList.length > 0) { |
|||
for (var i = 0; i < styleList.length; i++) { |
|||
var style = styleList[i]; |
|||
var counter = parseInt(style.getAttribute(styleCounterName)); |
|||
if (counter - 1 > 0) { |
|||
style.setAttribute(styleCounterName, counter - 1); |
|||
} else { |
|||
document.head.removeChild(style); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
let id = 0; |
|||
|
|||
export default { |
|||
created() { |
|||
if (this._.type.styles) { |
|||
if (!this._.type.uid) { |
|||
this._.type.uid = `uid_${id++}`; |
|||
} |
|||
addStyles(this._.type.uid, this._.type.styles); |
|||
} |
|||
}, |
|||
unmounted() { |
|||
removeStyles(this._.type.uid); |
|||
}, |
|||
}; |
@ -0,0 +1,90 @@ |
|||
import qs from "../lib/qs/shim.js"; |
|||
import { isLogin } from "../api/user.js"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import settings from "../config/settings.js"; |
|||
|
|||
const addToken = async (options) => { |
|||
if (await isLogin()) { |
|||
const appStore = useAppStore(); |
|||
options.headers ??= {}; |
|||
options.headers.Authorization = `Bearer ${appStore.token}`; |
|||
} |
|||
}; |
|||
|
|||
const getUrl = (url) => { |
|||
if (url.indexOf("/") === 0) { |
|||
return url; |
|||
} |
|||
let result = settings.baseURL; |
|||
return (result += `/${url}`); |
|||
}; |
|||
|
|||
const getResult = async (response) => { |
|||
const messages = new Map([ |
|||
[200, "操作成功"], |
|||
[201, "已创建"], |
|||
[204, "无返回值"], |
|||
[400, "请求参数错误"], |
|||
[401, "未登录"], |
|||
[403, "权限不足"], |
|||
[500, "服务器异常"], |
|||
]); |
|||
const result = { |
|||
status: response.status, |
|||
message: messages.get(response.status), |
|||
}; |
|||
if (response.status == 200) { |
|||
result.data = await response.json(); |
|||
} else if (response.status === 400 || response.status === 500) { |
|||
result.errors = await response.json(); |
|||
} |
|||
return result; |
|||
}; |
|||
|
|||
const get = async (url, data, options, withoutToken = false, withoutCulture = false) => { |
|||
url = getUrl(url, withoutCulture); |
|||
if (data) { |
|||
url = `${url}?${qs.stringify(data)}`; |
|||
} |
|||
const defaultOptions = { |
|||
headers: { |
|||
"Accept-Language": "zh-Hans", |
|||
}, |
|||
}; |
|||
if (options) { |
|||
Object.assign(defaultOptions, options); |
|||
} |
|||
if (!withoutToken) { |
|||
await addToken(defaultOptions); |
|||
} |
|||
const response = await fetch(url, defaultOptions); |
|||
return getResult(response); |
|||
}; |
|||
|
|||
const post = async (url, data, options, withoutToken = false, withoutCulture = false) => { |
|||
url = getUrl(url, withoutCulture); |
|||
const defaultOptions = { |
|||
method: "POST", |
|||
headers: { |
|||
"Accept-Language": "zh-Hans", |
|||
"Content-Type": "application/json", |
|||
}, |
|||
}; |
|||
if (options) { |
|||
Object.assign(defaultOptions, options); |
|||
} |
|||
if (data && !defaultOptions.body) { |
|||
if (defaultOptions.headers["Content-Type"] === "application/x-www-form-urlencoded") { |
|||
defaultOptions.body = qs.stringify(data); |
|||
} else { |
|||
defaultOptions.body = JSON.stringify(data); |
|||
} |
|||
} |
|||
if (!withoutToken) { |
|||
await addToken(defaultOptions); |
|||
} |
|||
const response = await fetch(url, defaultOptions); |
|||
return getResult(response); |
|||
}; |
|||
|
|||
export { getUrl, get, post }; |
@ -0,0 +1,314 @@ |
|||
var raf = null; |
|||
function requestAnimationFrame (callback) { |
|||
if (!raf) { |
|||
raf = ( |
|||
window.requestAnimationFrame || |
|||
window.webkitRequestAnimationFrame || |
|||
window.mozRequestAnimationFrame || |
|||
function (callback) { |
|||
return setTimeout(callback, 16) |
|||
} |
|||
).bind(window); |
|||
} |
|||
return raf(callback) |
|||
} |
|||
|
|||
var caf = null; |
|||
function cancelAnimationFrame (id) { |
|||
if (!caf) { |
|||
caf = ( |
|||
window.cancelAnimationFrame || |
|||
window.webkitCancelAnimationFrame || |
|||
window.mozCancelAnimationFrame || |
|||
function (id) { |
|||
clearTimeout(id); |
|||
} |
|||
).bind(window); |
|||
} |
|||
|
|||
caf(id); |
|||
} |
|||
|
|||
function createStyles (styleText) { |
|||
var style = document.createElement('style'); |
|||
|
|||
if (style.styleSheet) { |
|||
style.styleSheet.cssText = styleText; |
|||
} else { |
|||
style.appendChild(document.createTextNode(styleText)); |
|||
} |
|||
(document.querySelector('head') || document.body).appendChild(style); |
|||
return style |
|||
} |
|||
|
|||
function createElement (tagName, props) { |
|||
if ( props === void 0 ) props = {}; |
|||
|
|||
var elem = document.createElement(tagName); |
|||
Object.keys(props).forEach(function (key) { |
|||
elem[key] = props[key]; |
|||
}); |
|||
return elem |
|||
} |
|||
|
|||
function getComputedStyle (elem, prop, pseudo) { |
|||
// for older versions of Firefox, `getComputedStyle` required
|
|||
// the second argument and may return `null` for some elements
|
|||
// when `display: none`
|
|||
var computedStyle = window.getComputedStyle(elem, pseudo || null) || { |
|||
display: 'none' |
|||
}; |
|||
|
|||
return computedStyle[prop] |
|||
} |
|||
|
|||
function getRenderInfo (elem) { |
|||
if (!document.documentElement.contains(elem)) { |
|||
return { |
|||
detached: true, |
|||
rendered: false |
|||
} |
|||
} |
|||
|
|||
var current = elem; |
|||
while (current !== document) { |
|||
if (getComputedStyle(current, 'display') === 'none') { |
|||
return { |
|||
detached: false, |
|||
rendered: false |
|||
} |
|||
} |
|||
current = current.parentNode; |
|||
} |
|||
|
|||
return { |
|||
detached: false, |
|||
rendered: true |
|||
} |
|||
} |
|||
|
|||
var css_248z = ".resize-triggers{visibility:hidden;opacity:0;pointer-events:none}.resize-contract-trigger,.resize-contract-trigger:before,.resize-expand-trigger,.resize-triggers{content:\"\";position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden}.resize-contract-trigger,.resize-expand-trigger{background:#eee;overflow:auto}.resize-contract-trigger:before{width:200%;height:200%}"; |
|||
|
|||
var total = 0; |
|||
var style = null; |
|||
|
|||
function addListener (elem, callback) { |
|||
if (!elem.__resize_mutation_handler__) { |
|||
elem.__resize_mutation_handler__ = handleMutation.bind(elem); |
|||
} |
|||
|
|||
var listeners = elem.__resize_listeners__; |
|||
|
|||
if (!listeners) { |
|||
elem.__resize_listeners__ = []; |
|||
if (window.ResizeObserver) { |
|||
var offsetWidth = elem.offsetWidth; |
|||
var offsetHeight = elem.offsetHeight; |
|||
var ro = new ResizeObserver(function () { |
|||
if (!elem.__resize_observer_triggered__) { |
|||
elem.__resize_observer_triggered__ = true; |
|||
if (elem.offsetWidth === offsetWidth && elem.offsetHeight === offsetHeight) { |
|||
return |
|||
} |
|||
} |
|||
runCallbacks(elem); |
|||
}); |
|||
|
|||
// initially display none won't trigger ResizeObserver callback
|
|||
var ref = getRenderInfo(elem); |
|||
var detached = ref.detached; |
|||
var rendered = ref.rendered; |
|||
elem.__resize_observer_triggered__ = detached === false && rendered === false; |
|||
elem.__resize_observer__ = ro; |
|||
ro.observe(elem); |
|||
} else if (elem.attachEvent && elem.addEventListener) { |
|||
// targeting IE9/10
|
|||
elem.__resize_legacy_resize_handler__ = function handleLegacyResize () { |
|||
runCallbacks(elem); |
|||
}; |
|||
elem.attachEvent('onresize', elem.__resize_legacy_resize_handler__); |
|||
document.addEventListener('DOMSubtreeModified', elem.__resize_mutation_handler__); |
|||
} else { |
|||
if (!total) { |
|||
style = createStyles(css_248z); |
|||
} |
|||
initTriggers(elem); |
|||
|
|||
elem.__resize_rendered__ = getRenderInfo(elem).rendered; |
|||
if (window.MutationObserver) { |
|||
var mo = new MutationObserver(elem.__resize_mutation_handler__); |
|||
mo.observe(document, { |
|||
attributes: true, |
|||
childList: true, |
|||
characterData: true, |
|||
subtree: true |
|||
}); |
|||
elem.__resize_mutation_observer__ = mo; |
|||
} |
|||
} |
|||
} |
|||
|
|||
elem.__resize_listeners__.push(callback); |
|||
total++; |
|||
} |
|||
|
|||
function removeListener (elem, callback) { |
|||
var listeners = elem.__resize_listeners__; |
|||
if (!listeners) { |
|||
return |
|||
} |
|||
|
|||
if (callback) { |
|||
listeners.splice(listeners.indexOf(callback), 1); |
|||
} |
|||
|
|||
// no listeners exist, or removing all listeners
|
|||
if (!listeners.length || !callback) { |
|||
// targeting IE9/10
|
|||
if (elem.detachEvent && elem.removeEventListener) { |
|||
elem.detachEvent('onresize', elem.__resize_legacy_resize_handler__); |
|||
document.removeEventListener('DOMSubtreeModified', elem.__resize_mutation_handler__); |
|||
return |
|||
} |
|||
|
|||
if (elem.__resize_observer__) { |
|||
elem.__resize_observer__.unobserve(elem); |
|||
elem.__resize_observer__.disconnect(); |
|||
elem.__resize_observer__ = null; |
|||
} else { |
|||
if (elem.__resize_mutation_observer__) { |
|||
elem.__resize_mutation_observer__.disconnect(); |
|||
elem.__resize_mutation_observer__ = null; |
|||
} |
|||
elem.removeEventListener('scroll', handleScroll); |
|||
elem.removeChild(elem.__resize_triggers__.triggers); |
|||
elem.__resize_triggers__ = null; |
|||
} |
|||
elem.__resize_listeners__ = null; |
|||
} |
|||
|
|||
if (!--total && style) { |
|||
style.parentNode.removeChild(style); |
|||
} |
|||
} |
|||
|
|||
function getUpdatedSize (elem) { |
|||
var ref = elem.__resize_last__; |
|||
var width = ref.width; |
|||
var height = ref.height; |
|||
var offsetWidth = elem.offsetWidth; |
|||
var offsetHeight = elem.offsetHeight; |
|||
if (offsetWidth !== width || offsetHeight !== height) { |
|||
return { |
|||
width: offsetWidth, |
|||
height: offsetHeight |
|||
} |
|||
} |
|||
return null |
|||
} |
|||
|
|||
function handleMutation () { |
|||
// `this` denotes the scrolling element
|
|||
var ref = getRenderInfo(this); |
|||
var rendered = ref.rendered; |
|||
var detached = ref.detached; |
|||
if (rendered !== this.__resize_rendered__) { |
|||
if (!detached && this.__resize_triggers__) { |
|||
resetTriggers(this); |
|||
this.addEventListener('scroll', handleScroll, true); |
|||
} |
|||
this.__resize_rendered__ = rendered; |
|||
runCallbacks(this); |
|||
} |
|||
} |
|||
|
|||
function handleScroll () { |
|||
var this$1 = this; |
|||
|
|||
// `this` denotes the scrolling element
|
|||
resetTriggers(this); |
|||
if (this.__resize_raf__) { |
|||
cancelAnimationFrame(this.__resize_raf__); |
|||
} |
|||
this.__resize_raf__ = requestAnimationFrame(function () { |
|||
var updated = getUpdatedSize(this$1); |
|||
if (updated) { |
|||
this$1.__resize_last__ = updated; |
|||
runCallbacks(this$1); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
function runCallbacks (elem) { |
|||
if (!elem || !elem.__resize_listeners__) { |
|||
return |
|||
} |
|||
elem.__resize_listeners__.forEach(function (callback) { |
|||
callback.call(elem, elem); |
|||
}); |
|||
} |
|||
|
|||
function initTriggers (elem) { |
|||
var position = getComputedStyle(elem, 'position'); |
|||
if (!position || position === 'static') { |
|||
elem.style.position = 'relative'; |
|||
} |
|||
|
|||
elem.__resize_old_position__ = position; |
|||
elem.__resize_last__ = {}; |
|||
|
|||
var triggers = createElement('div', { |
|||
className: 'resize-triggers' |
|||
}); |
|||
var expand = createElement('div', { |
|||
className: 'resize-expand-trigger' |
|||
}); |
|||
var expandChild = createElement('div'); |
|||
var contract = createElement('div', { |
|||
className: 'resize-contract-trigger' |
|||
}); |
|||
expand.appendChild(expandChild); |
|||
triggers.appendChild(expand); |
|||
triggers.appendChild(contract); |
|||
elem.appendChild(triggers); |
|||
|
|||
elem.__resize_triggers__ = { |
|||
triggers: triggers, |
|||
expand: expand, |
|||
expandChild: expandChild, |
|||
contract: contract |
|||
}; |
|||
|
|||
resetTriggers(elem); |
|||
elem.addEventListener('scroll', handleScroll, true); |
|||
|
|||
elem.__resize_last__ = { |
|||
width: elem.offsetWidth, |
|||
height: elem.offsetHeight |
|||
}; |
|||
} |
|||
|
|||
function resetTriggers (elem) { |
|||
var ref = elem.__resize_triggers__; |
|||
var expand = ref.expand; |
|||
var expandChild = ref.expandChild; |
|||
var contract = ref.contract; |
|||
|
|||
// batch read
|
|||
var csw = contract.scrollWidth; |
|||
var csh = contract.scrollHeight; |
|||
var eow = expand.offsetWidth; |
|||
var eoh = expand.offsetHeight; |
|||
var esw = expand.scrollWidth; |
|||
var esh = expand.scrollHeight; |
|||
|
|||
// batch write
|
|||
contract.scrollLeft = csw; |
|||
contract.scrollTop = csh; |
|||
expandChild.style.width = eow + 1 + 'px'; |
|||
expandChild.style.height = eoh + 1 + 'px'; |
|||
expand.scrollLeft = esw; |
|||
expand.scrollTop = esh; |
|||
} |
|||
|
|||
export { addListener, removeListener }; |
@ -0,0 +1,133 @@ |
|||
import { createRouter, createWebHashHistory } from "vue-router"; |
|||
import { useTitle } from "@vueuse/core"; |
|||
import NProgress from "../lib/nprogress/nprogress.vite-esm.js"; |
|||
import { isLogin, hasPermission } from "../api/user.js"; |
|||
import { useAppStore } from "../store/index.js"; |
|||
import { listToTree } from "../utils/index.js"; |
|||
import { connection, connect } from "../signalr/index.js"; |
|||
|
|||
NProgress.configure({ showSpinner: false }); |
|||
|
|||
const routes = [ |
|||
{ |
|||
path: "/", |
|||
redirect: "/home", |
|||
component: () => import("../layouts/index.js"), |
|||
children: [ |
|||
{ |
|||
path: "home", |
|||
component: () => import("../views/home.js"), |
|||
meta: { |
|||
title: "首页", |
|||
icon: "home", |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
path: "/login", |
|||
component: () => import("../views/login.js"), |
|||
meta: { |
|||
title: "登录", |
|||
}, |
|||
}, |
|||
{ |
|||
path: "/403", |
|||
component: () => import("../views/403.js"), |
|||
meta: { |
|||
title: "权限不足", |
|||
}, |
|||
}, |
|||
{ |
|||
path: "/:pathMatch(.*)*", |
|||
component: () => import("../views/404.js"), |
|||
meta: { |
|||
title: "无法找到", |
|||
}, |
|||
}, |
|||
]; |
|||
|
|||
const router = createRouter({ |
|||
history: createWebHashHistory(), |
|||
routes, |
|||
}); |
|||
|
|||
router.beforeEach(async (to, from, next) => { |
|||
console.log(`before: ${from.path} -> ${to.path}`); |
|||
NProgress.start(); |
|||
try { |
|||
if (to.path !== "/login") { |
|||
if (!(await isLogin())) { |
|||
next({ path: "/login", query: { redirect: to.fullPath } }); |
|||
} else { |
|||
if (!hasPermission(to)) { |
|||
next({ path: "/403", query: { redirect: to.fullPath } }); |
|||
} else { |
|||
next(); |
|||
} |
|||
} |
|||
} else { |
|||
next(); |
|||
} |
|||
} catch (error) { |
|||
NProgress.done(); |
|||
} |
|||
}); |
|||
|
|||
router.afterEach((to, from) => { |
|||
console.log(`after: ${from.path} -> ${to.path}`); |
|||
try { |
|||
if (to.meta.title) { |
|||
useTitle().value = `${to.meta.title}`; |
|||
} |
|||
if (to.fullPath.startsWith("/")) { |
|||
const appStore = useAppStore(); |
|||
appStore.add(to); |
|||
} |
|||
} finally { |
|||
NProgress.done(); |
|||
} |
|||
}); |
|||
|
|||
const reset = (list, parent = null) => { |
|||
return list.map((o) => { |
|||
const item = { |
|||
path: o.path, |
|||
meta: o.meta, |
|||
}; |
|||
if (item.component && item.component !== "Layout") { |
|||
item.component = import(`../views/${o.component ? o.component : "list"}.js`); |
|||
} |
|||
item.meta.path = `${parent === null ? "" : parent.meta.path + "/"}${item.path}`; |
|||
item.meta.fullName = `${parent === null ? "" : parent.meta.title + " > "}${item.meta.title}`; |
|||
if (o.type === "Resource") { |
|||
if (o.children.length) { |
|||
item.meta.buttons = o.children.map((b) => { |
|||
return { |
|||
path: b.path, |
|||
meta: b.meta, |
|||
}; |
|||
}); |
|||
} |
|||
} else if (o.type !== "Operation" && o.children?.length) { |
|||
item.children = reset(o.children, item); |
|||
} |
|||
return item; |
|||
}); |
|||
}; |
|||
|
|||
const refreshRouter = async () => { |
|||
await connect(); |
|||
const appStore = useAppStore(); |
|||
const permissions = appStore.user.permissions.filter((o) => !o.isHidden); |
|||
const serverRoutes = reset(permissions); |
|||
const route = { |
|||
name: "layout", |
|||
path: "", |
|||
children: serverRoutes, |
|||
}; |
|||
router.removeRoute("layout"); |
|||
router.addRoute("/", route); |
|||
}; |
|||
export default router; |
|||
export { refreshRouter }; |
@ -0,0 +1,42 @@ |
|||
import * as signalR from "@microsoft/signalr"; |
|||
import PubSub from "pubsub-js"; |
|||
import useAppStore from "../store/app.js"; |
|||
import { isLogin } from "../api/user.js"; |
|||
|
|||
let connectionId = null; |
|||
const connection = new signalR.HubConnectionBuilder() |
|||
.withUrl("./api/hub", { |
|||
accessTokenFactory: () => { |
|||
const appStore = useAppStore(); |
|||
return appStore.token; |
|||
}, |
|||
}) |
|||
.withAutomaticReconnect() |
|||
.build(); |
|||
const connect = async () => { |
|||
return; |
|||
if (await isLogin()) { |
|||
if (connection.state === signalR.HubConnectionState.Disconnected) { |
|||
connection |
|||
.start() |
|||
.then(function () { |
|||
console.log("signalr connected"); |
|||
}) |
|||
.catch(function (error) { |
|||
console.error(error); |
|||
//setTimeout(connect, 5000);
|
|||
}); |
|||
} |
|||
} |
|||
}; |
|||
connection.onclose(async () => { |
|||
await connect(); |
|||
}); |
|||
connection.on("connected", (id) => { |
|||
connectionId = id; |
|||
}); |
|||
connection.on("ServerToClient", (method, data) => { |
|||
PubSub.publish(method, data); |
|||
}); |
|||
|
|||
export { connection, connect }; |
@ -0,0 +1,41 @@ |
|||
import { defineStore } from "pinia"; |
|||
import settings from "../config/settings.js"; |
|||
import { getUser, isLogin } from "../api/user.js"; |
|||
import { get, post } from "../request/index.js"; |
|||
import { refreshRouter } from "../router/index.js"; |
|||
import { getLocalizationAsync } from "../api/site.js"; |
|||
|
|||
const useAppStore = defineStore("app", { |
|||
state: () => { |
|||
const state = { |
|||
settings: { ...settings }, |
|||
isMenuCollapse: false, |
|||
isRefreshing: false, |
|||
routes: [], |
|||
}; |
|||
const localSettings = JSON.parse(localStorage.getItem("settings") ?? "{}"); |
|||
Object.assign(state.settings, localSettings); |
|||
return state; |
|||
}, |
|||
actions: { |
|||
async init() { |
|||
// 获取站点信息
|
|||
this.localization = await getLocalizationAsync(); |
|||
// 获取用户信息
|
|||
if (await isLogin()) { |
|||
this.user = await getUser(); |
|||
await refreshRouter(); |
|||
} |
|||
}, |
|||
add(route) { |
|||
if (!this.routes.find((o) => o.fullPath === route.fullPath)) { |
|||
this.routes.push(route); |
|||
} else { |
|||
const index = this.routes.findIndex((o) => o.fullPath === route.fullPath); |
|||
this.routes[index] = route; |
|||
} |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
export default useAppStore; |
@ -0,0 +1,7 @@ |
|||
import { createPinia } from 'pinia'; |
|||
import useAppStore from './app.js'; |
|||
|
|||
const store = createPinia(); |
|||
|
|||
export { useAppStore }; |
|||
export default store; |
@ -0,0 +1,137 @@ |
|||
html * { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
html, |
|||
body { |
|||
width: 100%; |
|||
height: 100%; |
|||
margin: 0; |
|||
padding: 0; |
|||
text-rendering: optimizeLegibility; |
|||
} |
|||
|
|||
a { |
|||
color: inherit; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
#app { |
|||
width: 100vw; |
|||
height: 100vh; |
|||
--header: 60px; |
|||
} |
|||
|
|||
#app > .el-container { |
|||
width: 100%; |
|||
height: 100%; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
#app > .el-container > .el-container { |
|||
margin-top: var(--header); |
|||
height: calc(100% - var(--header)); |
|||
overflow: auto; |
|||
} |
|||
|
|||
.el-scrollbar, |
|||
.el-scrollbar__view { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.el-aside { |
|||
min-height: 100%; |
|||
overflow: auto; |
|||
} |
|||
|
|||
.el-menu--vertical { |
|||
min-height: 100%; |
|||
} |
|||
|
|||
.el-main { |
|||
min-height: calc(100% - 100px); |
|||
overflow: auto; |
|||
} |
|||
|
|||
.el-header { |
|||
width: 100%; |
|||
position: fixed; |
|||
border-bottom: 1px solid var(--el-border-color); |
|||
background-color: var(--el-menu-bg-color); |
|||
z-index: 10; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.el-footer { |
|||
width: 100%; |
|||
border-top: 1px solid var(--el-border-color); |
|||
background-color: var(--el-menu-bg-color); |
|||
overflow: hidden; |
|||
} |
|||
|
|||
a.logo { |
|||
display: block; |
|||
height: var(--header); |
|||
} |
|||
|
|||
.footer { |
|||
height: var(--header); |
|||
} |
|||
|
|||
.logo img { |
|||
min-width: 28px; |
|||
height: 28px; |
|||
margin-right: 16px; |
|||
} |
|||
|
|||
.logo h1 { |
|||
height: 32px; |
|||
line-height: 32px; |
|||
padding-right: 20px; |
|||
} |
|||
|
|||
.el-dropdown-link:focus-visible { |
|||
outline: unset; |
|||
} |
|||
|
|||
.el-form--inline .el-form-item__content { |
|||
width: 192px; |
|||
} |
|||
|
|||
.el-table .cell { |
|||
white-space: nowrap; |
|||
} |
|||
|
|||
.el-icon { |
|||
margin-right: 5px; |
|||
} |
|||
|
|||
.el-dialog__header, |
|||
.el-dialog__footer, |
|||
.el-drawer__header, |
|||
.el-drawer__footer { |
|||
height: var(--header); |
|||
padding: 15px; |
|||
} |
|||
|
|||
.el-dialog__header, |
|||
.el-drawer__header { |
|||
border-bottom: 1px solid var(--el-border-color); |
|||
} |
|||
|
|||
.el-dialog__footer, |
|||
.el-drawer__footer { |
|||
border-top: 1px solid var(--el-border-color); |
|||
} |
|||
|
|||
.el-select, |
|||
.el-input-number { |
|||
width: 100%; |
|||
} |
|||
|
|||
/* markdown component */ |
|||
.markdown-body { |
|||
box-sizing: border-box; |
|||
margin: 0 auto; |
|||
} |
@ -0,0 +1,120 @@ |
|||
import { get } from "lodash"; |
|||
|
|||
// format html`...` by vscode lit-html
|
|||
function html(strings, ...values) { |
|||
let output = ""; |
|||
let index; |
|||
for (index = 0; index < values.length; index += 1) { |
|||
output += strings[index] + values[index]; |
|||
} |
|||
output += strings[index]; |
|||
return output; |
|||
} |
|||
|
|||
// format %
|
|||
function persentFormat(number) { |
|||
return `${parseFloat(number * 100).toFixed(2)} %`; |
|||
} |
|||
// format bytes
|
|||
function bytesFormat(bytes) { |
|||
if (isNaN(bytes)) { |
|||
return ""; |
|||
} |
|||
var symbols = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; |
|||
var exp = Math.floor(Math.log(bytes) / Math.log(2)); |
|||
if (exp < 1) { |
|||
exp = 0; |
|||
} |
|||
var i = Math.floor(exp / 10); |
|||
bytes = bytes / Math.pow(2, 10 * i); |
|||
|
|||
if (bytes.toString().length > bytes.toFixed(2).toString().length) { |
|||
bytes = bytes.toFixed(2); |
|||
} |
|||
return bytes + " " + symbols[i]; |
|||
} |
|||
|
|||
// string format
|
|||
function format(template, ...args) { |
|||
const formatRegExp = /%[sdj%]/g; |
|||
let counter = 0; |
|||
return template.replace(formatRegExp, (match) => { |
|||
const index = counter; |
|||
counter += 1; |
|||
if (match === "%%") { |
|||
return "%"; |
|||
} |
|||
if (index > args.length - 1) { |
|||
return match; |
|||
} |
|||
if (match === "%s") { |
|||
return String(args[index]); |
|||
} |
|||
if (match === "%d") { |
|||
return Number(args[index]); |
|||
} |
|||
if (match === "%j") { |
|||
return JSON.stringify(args[index]); |
|||
} |
|||
return match; |
|||
}); |
|||
} |
|||
|
|||
function schemaToModel(schema) { |
|||
const entity = {}; |
|||
Object.keys(schema.properties).forEach((propertyName) => { |
|||
const property = schema.properties[propertyName]; |
|||
if (property.type === "object") { |
|||
entity[propertyName] = schemaToModel(property); |
|||
} else if ("default" in property) { |
|||
entity[propertyName] = property.default; |
|||
} else if (property.type === "array") { |
|||
entity[propertyName] = []; |
|||
} else if (property.type === "boolean") { |
|||
entity[propertyName] = property.nullable ? null : false; |
|||
} else if (property.type === "number" || property.type === "integer") { |
|||
entity[propertyName] = property.nullable ? null : 0; |
|||
} else if (property.type === "string") { |
|||
entity[propertyName] = null; |
|||
} else { |
|||
entity[propertyName] = null; |
|||
} |
|||
}); |
|||
return entity; |
|||
} |
|||
|
|||
function listToTree(list, func) { |
|||
const tree = []; |
|||
list.forEach((item) => { |
|||
if (!item.parentId) { |
|||
tree.push(item); |
|||
} else { |
|||
const parent = list.find((node) => node.id === item.parentId); |
|||
if (parent) { |
|||
parent.children = parent.children || []; |
|||
parent.children.push(item); |
|||
} |
|||
} |
|||
if (func) { |
|||
func(item); |
|||
} |
|||
}); |
|||
return tree; |
|||
} |
|||
|
|||
function treeToList(tree, list = []) { |
|||
tree.forEach((o) => { |
|||
list.push(o); |
|||
if (o.children?.length) { |
|||
treeToList(o.children, list); |
|||
} |
|||
}); |
|||
return list; |
|||
} |
|||
|
|||
function getProp(instance, propPath) { |
|||
return get(instance, propPath); |
|||
} |
|||
|
|||
export default html; |
|||
export { persentFormat, bytesFormat, format, schemaToModel, listToTree, treeToList, getProp }; |
@ -0,0 +1,3 @@ |
|||
export default { |
|||
template: `403`, |
|||
}; |
@ -0,0 +1,3 @@ |
|||
export default { |
|||
template: `404:{{$route}}`, |
|||
}; |
@ -0,0 +1,7 @@ |
|||
import html from 'html'; |
|||
import Md from '../components/markdown/index.js' |
|||
|
|||
export default { |
|||
components: { Md }, |
|||
template: html`Home <md name="test"></md>` |
|||
} |
@ -0,0 +1,32 @@ |
|||
import AppList from "../components/list/index.js"; |
|||
import html from "html"; |
|||
import router from "../router/index.js"; |
|||
|
|||
export default { |
|||
components: { AppList }, |
|||
template: html`<el-scrollbar>
|
|||
<app-list @command="onCommand"> |
|||
<template #columns="scope"> |
|||
<el-table-column label="自定义列测试1" prop="id"> |
|||
<template #default="scope"> {{scope.row.id}} </template> |
|||
</el-table-column> |
|||
<el-table-column label="自定义列测试2"> |
|||
<template #default="scope"> {{scope.row.parent?.id}} </template> |
|||
</el-table-column> |
|||
</template> |
|||
<template #tableButtons="{rows}"> |
|||
<el-button class="el-button--primary" @click="()=>(console.log(rows))">{{$t('test')}}</el-button> |
|||
</template> |
|||
<template #rowButtons="{rows}"> |
|||
<el-button class="el-button--primary" @click="()=>(console.log(rows))">{{$t('test')}}</el-button> |
|||
</template> |
|||
</app-list> |
|||
</el-scrollbar>`, |
|||
setup() { |
|||
console.log(router.currentRoute.value.fullPath); |
|||
const onCommand = (item, rows) => { |
|||
console.log(item.path, item, rows); |
|||
}; |
|||
return { onCommand }; |
|||
}, |
|||
}; |
@ -0,0 +1,90 @@ |
|||
import html, { schemaToModel } from "html"; |
|||
import { ref, reactive } from "vue"; |
|||
import AppForm from "../components/form/index.js"; |
|||
import { login } from "../api/user.js"; |
|||
import { get } from "../request/index.js"; |
|||
import LayoutLogo from "../layouts/logo.js"; |
|||
import LayoutLocale from "../layouts/locale.js"; |
|||
import LayoutFooter from "../layouts/footer.js"; |
|||
|
|||
export default { |
|||
components: { AppForm, LayoutLogo, LayoutLocale, LayoutFooter }, |
|||
template: html`<el-container>
|
|||
<el-main class="flex justify-center"> |
|||
<div> |
|||
<div class="flex items-center justify-center"> |
|||
<layout-logo /> |
|||
<layout-locale /> |
|||
</div> |
|||
<el-card class="box-card" style="width:400px;"> |
|||
<app-form :schema="schema" v-model="model" :action="action" @submit="submit">{{$t('login')}}</app-form> |
|||
</el-card> |
|||
<layout-footer /> |
|||
</div> |
|||
</el-main> |
|||
</el-container>`, |
|||
async setup() { |
|||
const schema = reactive({ |
|||
title: "LoginRequestModel", |
|||
type: "object", |
|||
properties: { |
|||
username: { |
|||
title: "用户名", |
|||
type: "string", |
|||
rules: [ |
|||
{ |
|||
required: true, |
|||
message: "用户名不能为空", |
|||
}, |
|||
{ |
|||
max: 64, |
|||
message: "用户名的最大长度为 64", |
|||
}, |
|||
], |
|||
}, |
|||
password: { |
|||
title: "密码", |
|||
type: "string", |
|||
format: "password", |
|||
rules: [ |
|||
{ |
|||
required: true, |
|||
message: "密码不能为空", |
|||
}, |
|||
{ |
|||
max: 64, |
|||
message: "密码的最大长度为 64", |
|||
}, |
|||
{ |
|||
message: "DataTypeAttribute", |
|||
}, |
|||
], |
|||
}, |
|||
client_id: { |
|||
default: "basic-web", |
|||
hidden: true, |
|||
}, |
|||
grant_type: { |
|||
default: "password", |
|||
hidden: true, |
|||
}, |
|||
scope: { |
|||
default: "WebAppGateway BaseService", |
|||
hidden: true, |
|||
}, |
|||
}, |
|||
}); |
|||
const model = reactive(schemaToModel(schema)); |
|||
const submit = async (callback) => { |
|||
const result = await login(model); |
|||
if (result.errors) { |
|||
callback(result.errors); |
|||
} |
|||
}; |
|||
return { |
|||
schema, |
|||
model, |
|||
submit, |
|||
}; |
|||
}, |
|||
}; |
@ -0,0 +1,216 @@ |
|||
import html from "html"; |
|||
import { ref, reactive, onMounted, onUnmounted } from "vue"; |
|||
import { useRoute } from "vue-router"; |
|||
import Chart from "../components/chart/index.js"; |
|||
import { get, post } from "../request/index.js"; |
|||
import { ElMessage, dayjs } from "element-plus"; |
|||
import { bytesFormat, persentFormat } from "../utils/index.js"; |
|||
import PubSub from "pubsub-js"; |
|||
|
|||
export default { |
|||
components: { Chart }, |
|||
template: html` <template v-if="model">
|
|||
<el-row :gutter="20" style="margin-bottom:20px;"> |
|||
<el-col :span="24"> |
|||
<el-card class="box-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>操作系统</span> |
|||
</div> |
|||
</template> |
|||
<el-descriptions border direction="vertical" :column="4"> |
|||
<el-descriptions-item label="架构">{{model.osArchitecture}}</el-descriptions-item> |
|||
<el-descriptions-item label="名称">{{model.osDescription}}</el-descriptions-item> |
|||
<el-descriptions-item label="主机">{{model.hostName}}</el-descriptions-item> |
|||
<el-descriptions-item label="用户">{{model.userName}}</el-descriptions-item> |
|||
<el-descriptions-item label="时间">{{dayjs(model.serverTime).format()}}</el-descriptions-item> |
|||
<el-descriptions-item label="地址">{{model.hostAddresses}}</el-descriptions-item> |
|||
<el-descriptions-item label="进程">{{model.processCount}}</el-descriptions-item> |
|||
<el-descriptions-item label="线程">{{model.threadCount}}</el-descriptions-item> |
|||
<el-descriptions-item label="名称">{{model.driveName}}</el-descriptions-item> |
|||
<el-descriptions-item label="大小">{{bytesFormat(model.drivieTotalSize)}}</el-descriptions-item> |
|||
<el-descriptions-item label="剩余">{{bytesFormat(model.driveAvailableFreeSpace)}}</el-descriptions-item> |
|||
<el-descriptions-item label="占用">{{persentFormat(1-model.driveAvailableFreeSpace/model.drivieTotalSize)}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row :gutter="20" style="margin-bottom:20px;"> |
|||
<el-col :span="12"> |
|||
<el-card class="box-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>处理器 {{model.processorCount}} </span> |
|||
</div> |
|||
</template> |
|||
<chart :option="cpuModel" height="300px" /> |
|||
</el-card> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-card class="box-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>内存 {{bytesFormat(model.totalMemory)}}</span> |
|||
</div> |
|||
</template> |
|||
<chart :option="memoryModel" height="300px" /> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row :gutter="20" style="margin-bottom:20px;"> |
|||
<el-col :span="12"> |
|||
<el-card class="box-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>磁盘</span> |
|||
</div> |
|||
</template> |
|||
<el-descriptions border direction="vertical"> |
|||
<el-descriptions-item label="读取">{{bytesFormat(model.diskRead)}}</el-descriptions-item> |
|||
<el-descriptions-item label="写入">{{bytesFormat(model.diskWrite)}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-card class="box-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>网络</span> |
|||
</div> |
|||
</template> |
|||
<el-descriptions border direction="vertical"> |
|||
<el-descriptions-item label="下载">{{bytesFormat(model.netReceived)}}</el-descriptions-item> |
|||
<el-descriptions-item label="上传">{{bytesFormat(model.netSent)}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row :gutter="20" style="margin-bottom:20px;"> |
|||
<el-col :span="24"> |
|||
<el-card class="box-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>.NET</span> |
|||
</div> |
|||
</template> |
|||
<el-descriptions border direction="vertical" :column="4"> |
|||
<el-descriptions-item label="名称">{{model.frameworkDescription}}</el-descriptions-item> |
|||
<el-descriptions-item label="已分配内存">{{bytesFormat(model.gcTotalMemory)}}</el-descriptions-item> |
|||
<el-descriptions-item label="可回收对象">{{model.finalizationPendingCount}}</el-descriptions-item> |
|||
<el-descriptions-item label="堆大小">{{bytesFormat(model.heapSizeBytes)}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row :gutter="20" style="margin-bottom:20px;"> |
|||
<el-col :span="24"> |
|||
<el-card class="box-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>应用</span> |
|||
</div> |
|||
</template> |
|||
<el-descriptions border direction="vertical" :column="5"> |
|||
<el-descriptions-item label="架构">{{model.processArchitecture}}</el-descriptions-item> |
|||
<el-descriptions-item label="启动时间">{{dayjs(model.processStartTime).format()}}</el-descriptions-item> |
|||
<el-descriptions-item label="启动位置">{{model.processFileName}}</el-descriptions-item> |
|||
<el-descriptions-item label="参数">{{model.processArguments}}</el-descriptions-item> |
|||
<el-descriptions-item label="进程Id">{{model.processId}}</el-descriptions-item> |
|||
<el-descriptions-item label="进程名称">{{model.processName}}</el-descriptions-item> |
|||
<el-descriptions-item label="CPU">{{persentFormat(model.processCpuUsage)}}</el-descriptions-item> |
|||
<el-descriptions-item label="内存">{{bytesFormat(model.processMemory)}}</el-descriptions-item> |
|||
<el-descriptions-item label="磁盘读写" |
|||
>{{bytesFormat(model.processDiskRead)}} / {{bytesFormat(model.processDiskWrite)}}</el-descriptions-item |
|||
> |
|||
<el-descriptions-item label="线程">{{model.processThreadCount}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
</template>`, |
|||
setup(props) { |
|||
const route = useRoute(); |
|||
const baseUrl = `${route.meta.path}`.substring(1); |
|||
const url = `${baseUrl}/index`; |
|||
const schema = reactive({}); |
|||
const model = reactive({}); |
|||
//
|
|||
const cpuModel = reactive({ |
|||
title: { |
|||
text: "处理器", |
|||
}, |
|||
xAxis: { |
|||
type: "category", |
|||
data: Object.keys(Array(30).fill()), |
|||
}, |
|||
yAxis: { |
|||
type: "value", |
|||
min: 0, |
|||
max: 100, |
|||
}, |
|||
series: [ |
|||
{ |
|||
data: [], |
|||
type: "line", |
|||
smooth: true, |
|||
}, |
|||
], |
|||
}); |
|||
|
|||
const memoryModel = reactive({ |
|||
title: { |
|||
text: "内存", |
|||
}, |
|||
xAxis: { |
|||
type: "category", |
|||
data: Object.keys(Array(30).fill()), |
|||
}, |
|||
yAxis: { |
|||
type: "value", |
|||
min: 0, |
|||
max: 100, |
|||
}, |
|||
series: [ |
|||
{ |
|||
data: [], |
|||
type: "bar", |
|||
smooth: true, |
|||
}, |
|||
], |
|||
}); |
|||
//
|
|||
const onMonitor = (method, data) => { |
|||
Object.assign(model, data); |
|||
// cpu
|
|||
if (cpuModel.series[0].data.length > 30) { |
|||
cpuModel.series[0].data.shift(); |
|||
} |
|||
cpuModel.title.text = `处理器 ${persentFormat(model.cpuUsage)}`; |
|||
cpuModel.series[0].data.push(model.cpuUsage * 100); |
|||
// memory
|
|||
if (memoryModel.series[0].data.length > 30) { |
|||
memoryModel.series[0].data.shift(); |
|||
} |
|||
memoryModel.title.text = `内存 ${persentFormat(model.memoryUsage)}`; |
|||
memoryModel.series[0].data.push(model.memoryUsage * 100); |
|||
}; |
|||
onMounted(async () => { |
|||
Object.assign(schema, (await get(url)).data); |
|||
Object.assign(model, (await post(url)).data); |
|||
PubSub.subscribe("monitor", onMonitor); |
|||
}); |
|||
onUnmounted(() => { |
|||
PubSub.unsubscribe(onMonitor); |
|||
}); |
|||
//
|
|||
return { |
|||
schema, |
|||
model, |
|||
cpuModel, |
|||
memoryModel, |
|||
dayjs, |
|||
bytesFormat, |
|||
persentFormat, |
|||
}; |
|||
}, |
|||
}; |