This commit is contained in:
oneao committed 2025-08-14 17:28:32 +08:00
1 parent d1b1aafc57
commit 0f1604c709
58 files changed
+15476 -25

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
+16
View File
@@ -0,0 +1,16 @@
VITE_BASE_URL=/
VITE_APP_TITLE=IIBTA-VUE
# icon图标前缀:iconify库相关
VITE_ICON_PREFIX = i
# icon本地图标前缀:本地相关
VITE_ICON_LOCAL_PREFIX = i-local
# 上传地址
VITE_UPLOAD_BASEURL = ''
# 是否开启代理 Y 开启 N 不开启
VITE_APP_PROXY= 'Y'
# 代理地址
VITE_APP_PROXY_PREFIX = '/api'
+4
View File
@@ -0,0 +1,4 @@
ENV = 'prod'
VITE_SERVER_BASEURL = ''
+3
View File
@@ -0,0 +1,3 @@
ENV = 'test'
VITE_SERVER_BASEURL = ''
+28
View File
@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
+14
View File
@@ -0,0 +1,14 @@
{
"recommendations": [
"afzalsayed96.icones",
"antfu.iconify",
"antfu.unocss",
"dbaeumer.vscode-eslint",
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"mhutchie.git-graph",
"mikestead.dotenv",
"sdras.vue-vscode-snippets",
"vue.volar",
]
}
+22
View File
@@ -0,0 +1,22 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
"editor.formatOnSave": false,
"eslint.validate": [
"html",
"css",
"scss",
"json",
"jsonc",
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"prettier.enable": false,
"typescript.tsdk": "node_modules/typescript/lib",
"unocss.root": ["./"]
}
+15
View File
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="light dark" />
<title>%VITE_APP_TITLE%</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
+63
View File
@@ -0,0 +1,63 @@
{
"name": "iibta-vue",
"type": "module",
"version": "1.0.0",
"description": "",
"author": {
"name": "ONEAO",
"email": "hi_itao@163.com"
},
"engines": {
"node": ">=18.12.0",
"pnpm": ">=8.7.0"
},
"scripts": {
"build": "vite build --mode prod",
"build:test": "vite build --mode test",
"dev": "vite --mode test",
"dev:prod": "vite --mode prod",
"preview": "vite preview"
},
"dependencies": {
"@better-scroll/core": "2.5.1",
"@iconify/vue": "4.3.0",
"@vueuse/core": "12.4.0",
"axios": "^1.7.9",
"clipboard": "2.0.11",
"dayjs": "1.11.13",
"json5": "2.2.3",
"nprogress": "0.2.0",
"pinia": "2.3.0",
"pinia-plugin-persistedstate": "^4.2.0",
"qs": "^6.14.0",
"tailwind-merge": "2.6.0",
"vue": "3.5.13",
"vue-router": "4.5.0"
},
"devDependencies": {
"@iconify-json/material-symbols": "^1.2.15",
"@iconify/json": "2.2.297",
"@iconify/utils": "^2.2.1",
"@types/node": "22.10.7",
"@types/nprogress": "0.2.3",
"@unocss/preset-icons": "65.4.2",
"@unocss/preset-uno": "65.4.2",
"@unocss/transformer-directives": "65.4.2",
"@unocss/transformer-variant-group": "65.4.2",
"@unocss/vite": "65.4.2",
"@vitejs/plugin-vue": "5.2.1",
"@vitejs/plugin-vue-jsx": "4.1.1",
"globals": "^15.14.0",
"sass": "1.83.4",
"tsx": "4.19.2",
"typescript": "5.7.3",
"unplugin-icons": "22.0.0",
"unplugin-vue-components": "28.0.0",
"vite": "6.0.7",
"vite-plugin-progress": "0.0.7",
"vite-plugin-svg-icons": "2.0.1",
"vite-plugin-vue-devtools": "7.7.0",
"vue-tsc": "2.2.0"
},
"website": "https://user-template.cn"
}
+6055
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#646cff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#646cff"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

+6
View File
@@ -0,0 +1,6 @@
<template>
<router-view></router-view>
</template>
<script setup lang="ts"></script>
<style scoped></style>
@@ -0,0 +1,54 @@
<script setup lang="ts">
import { computed, useAttrs } from 'vue';
import { Icon } from '@iconify/vue';
defineOptions({ name: 'SvgIcon', inheritAttrs: false });
/**
* Props
*
* - Support iconify and local svg icon
* - If icon and localIcon are passed at the same time, localIcon will be rendered first
*/
interface Props {
/** Iconify icon name */
icon?: string;
/** Local svg icon name */
localIcon?: string;
}
const props = defineProps<Props>();
const attrs = useAttrs();
const bindAttrs = computed<{ class: string; style: string }>(() => ({
class: (attrs.class as string) || '',
style: (attrs.style as string) || ''
}));
const symbolId = computed(() => {
const { VITE_ICON_LOCAL_PREFIX: prefix } = import.meta.env;
const defaultLocalIcon = 'no-icon';
const icon = props.localIcon || defaultLocalIcon;
return `#${prefix}-${icon}`;
});
/** If localIcon is passed, render localIcon first */
const renderLocalIcon = computed(() => props.localIcon || !props.icon);
</script>
<template>
<template v-if="renderLocalIcon">
<svg aria-hidden="true" width="1em" height="1em" v-bind="bindAttrs">
<use :xlink:href="symbolId" fill="currentColor" />
</svg>
</template>
<template v-else>
<Icon v-if="icon" :icon="icon" v-bind="bindAttrs" />
</template>
</template>
<style scoped></style>
@@ -0,0 +1,136 @@
import axios, { AxiosInstance, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from "axios";
import { Message } from "@arco-design/web-vue";
import { useRouterStore } from "@/store/router";
import { useUserStore } from "@/store/user";
import { ResponseStatusEnum, ResponseStatusErrorMessageEnum } from "@/types/enums"
const buildBaseUrl = () => {
const isProxy = import.meta.env.VITE_APP_PROXY === "Y";
const mode = import.meta.env.MODE;
const proxyPrefix = import.meta.env.VITE_APP_PROXY_PREFIX;
const baseURL = import.meta.env.VITE_SERVER_BASEURL;
if (mode === "prod") {
if (isProxy) {
return baseURL + proxyPrefix;
} else {
return baseURL;
}
} else {
if (isProxy) {
return proxyPrefix;
} else {
return baseURL;
}
}
};
const axiosInstance: AxiosInstance = axios.create({
baseURL: buildBaseUrl(),
timeout: 0
});
// 请求拦截器
axiosInstance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
const userStore = useUserStore();
const noFreePaths = ["/imMessage/**"];
const path = config.url || "";
const needAuth = noFreePaths.some((pattern) => {
const regex = new RegExp(
pattern
.replace(/(\/\*\*)/g, "(/.*)?")
.replace(/(\/\*)/g, "(/[^/]*)?")
.replace(/\./g, "\\.") + "$"
);
return regex.test(path);
});
if (needAuth) {
userStore.clearUserInfo();
return Promise.reject(new Error("尚未登录,请先登录!"));
}
// 如果 token 存在,添加到请求头
config.headers["Authorization"] = `Bearer ${userStore.userInfo.token}`;
config.headers["id"] = userStore.userInfo.id;
return config;
},
(error: AxiosError) => {
return Promise.reject(error);
}
);
axiosInstance.interceptors.response.use(
(response: AxiosResponse) => {
// 判断响应是否为文件下载类型(例如 application/octet-stream)
const isDownload = isDownloadResponse(response.headers);
// 如果是文件下载,直接返回响应数据,不做其他处理
if (isDownload) {
return response;
}
// 如果不是文件下载,继续进行错误处理和数据解析
if (response.status !== 200) {
Message.error("请求错误");
return Promise.reject();
}
const resData = response.data as IResData;
// 解析返回数据中的字段
response.data.data = parseJsonOrReturnString(response.data.data);
const routerStore = useRouterStore();
const userStore = useUserStore();
if (resData.code >= 200 && resData.code < 300) {
return Promise.resolve(response.data);
} else if (resData.code >= 400 && resData.code <= 500) {
Message.error(resData.message || "请求错误");
switch (resData.code) {
case ResponseStatusEnum.UNAUTHORIZED:
if (routerStore.getCurrentPath() !== "/login") {
userStore.clearUserInfo();
routerStore.toPath("/login");
}
}
return Promise.reject(resData);
} else {
Message.error(resData.message || "请求错误");
return Promise.reject(resData);
}
},
(error: AxiosError) => {
// 网络错误处理
switch (error.message) {
case ResponseStatusErrorMessageEnum.NO_LOGIN:
Message.error(ResponseStatusErrorMessageEnum.NO_LOGIN);
break;
default:
// 其他情况提示网络错误
Message.error("网络错误,请换个网络试试!");
}
}
);
function isDownloadResponse(headers: any): boolean {
const contentType = headers["content-type"];
return /application\/(octet-stream|force-download|pdf|vnd.ms-excel|msexcel|OCTET-STREAM)/.test(contentType || "");
}
function parseJsonOrReturnString(input: any) {
try {
// 尝试解析输入字符串
return JSON.parse(input); // 如果成功,返回解析后的内容
} catch {
// 如果解析失败,则返回原始字符串
return input;
}
}
export default axiosInstance;
@@ -0,0 +1,15 @@
<template>
<Topbar></Topbar>
<Center></Center>
<Footer></Footer>
</template>
<script setup lang="ts">
import Topbar from "../topbar/index.vue";
import Center from "../center/index.vue";
import Footer from "../footer/index.vue";
</script>
<style lang="scss" scoped>
</style>
@@ -0,0 +1,7 @@
<template>
<router-view></router-view>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped></style>
@@ -0,0 +1,14 @@
<template>
<div class="footer">footer</div>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
.footer {
width: 100%;
padding-bottom: 20px;
margin-top: 88px;
background: #efeff1;
}
</style>
@@ -0,0 +1,75 @@
<template>
<header class="ys-header__top clearfix">
<div class="mt-talgm container">
<div class="c row">
<div class="ww-twybf ys-header_bd clearfix">
<div class="tp-gbkrn ys-header__logo" style="padding-top: 5px;">
<a class="logo">
<img class="img-responsive hidden-xs" src="/static/images/logo.gif" style="width:150px;height:50px"></img>
<img class="img-responsive visible-xs" src="/static/images/logo.gif" style="width:120px;height:40px"></img>
</a>
</div>
<ul class="ys-header__menu nav-menu">
<li class="hidden-sm hidden-xs"><a>首页</a></li>
<li class="visible-inline-lg"><a href="/s/film/">电影</a></li>
<li class="visible-inline-lg"><a href="/s/juji/">剧集</a></li>
<li class="visible-inline-lg"><a href="/s/variety/">综艺</a></li>
<li class="visible-inline-lg"><a href="/s/animation/">动漫</a></li>
<li class="visible-inline-lg"><a href="http://xs.iibta.com/">小说</a></li>
<li class="dropdown-hover">
<a href="javascript:;">频道 <i class="fa fa-angle-down"></i></a>
<div class="ho-qgtxn dropdown-box bottom fadeInDown clearfix" style="">
<ul class="item nav-list clearfix">
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/">首页</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/film/">电影</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/juji/">剧集</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/variety/">综艺</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/animation/">动漫</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/news/information/">资讯</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/actor/type/id/star.html">明星</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/ancient/">古装</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/adventure/">冒险</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/suspense/">悬疑</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/crime/">犯罪</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/fantasy/">奇幻</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/thriller/">惊悚</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/disaster/">灾难</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/micro/">微电影</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/record/">记录</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/ethical/">理伦</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/others/">其它</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/action/">动作</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/comedy/">喜剧</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/s/romance/">爱情</a></li>
<li class="col-lg-5 col-md-5 col-sm-5 col-xs-3"><a class="btn btn-sm btn-block btn-default" href="/star/">明星</a></li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</div>
</header>
</template>
<script setup lang="ts">
</script>
<style lang="scss" scoped>
@media (width >= 1400px) {
.container {
padding-right: 120px;
padding-left: 120px;
}
}
@media (width >= 1400px) {
.container {
max-width: 1920px;
}
}
</style>
+17
View File
@@ -0,0 +1,17 @@
import { createApp } from "vue";
import "./plugins/assets";
import { setupNProgress } from "./plugins/index";
import { setupPinia } from "./store";
import { setupRouter } from "./router/index";
import App from "./App.vue";
async function setupApp() {
setupNProgress();
const app = createApp(App);
setupPinia(app);
setupRouter(app);
app.mount("#app");
}
setupApp();
@@ -0,0 +1,13 @@
<template>
<div class="about">
<div></div>
</div>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
.about {
margin-top: 70px;
}
</style>
@@ -0,0 +1,11 @@
<template>
<div class="home">Home</div>
</template>
<script setup lang="ts"></script>
<style lang="scss" scoped>
.home {
margin-top: 70px;
}
</style>
@@ -0,0 +1,3 @@
// import "uno.css";
// import "virtual:svg-icons-register";
import "../styles/css/global.css";
@@ -0,0 +1 @@
export * from "./nprocess";
@@ -0,0 +1,7 @@
import NProgress from "nprogress";
export function setupNProgress() {
NProgress.configure({ easing: "ease", speed: 500 });
window.NProgress = NProgress;
}
+24
View File
@@ -0,0 +1,24 @@
import type { App } from "vue";
import { createRouter, createWebHashHistory } from "vue-router";
import routes from "./routes";
const router = createRouter({
history: createWebHashHistory(),
strict: true,
routes: routes,
scrollBehavior: () => ({ left: 0, top: 0 }),
});
router.beforeEach((to, from, next) => {
window.NProgress?.start?.();
next();
});
router.afterEach(() => {
window.NProgress?.done?.();
});
export function setupRouter(app: App) {
app.use(router);
}
+26
View File
@@ -0,0 +1,26 @@
import { RouteRecordRaw } from "vue-router";
import BaseLayout from "@/layouts/base-layout/index.vue";
import Home from "@/pages/home/index.vue";
import AboutUs from "@/pages/aboutUs/index.vue";
const routes: RouteRecordRaw[] = [
{
path: "/",
component: BaseLayout,
redirect: "/home",
children: [
{
path: "/home",
component: Home
},
{
path: "/aboutUs",
component: AboutUs
},
]
},
];
export default routes;
+11
View File
@@ -0,0 +1,11 @@
import { httpGet } from "@/utils/http";
export interface AreaType {
label: string;
value: number;
children?: AreaType[];
}
export const getAreaTreeDataApi = () => {
return httpGet<AreaType[]>(`/area/getTreeData`);
};
+9
View File
@@ -0,0 +1,9 @@
import type { App } from "vue";
import { createPinia } from "pinia";
import { createPersistedState } from "pinia-plugin-persistedstate"; // 数据持久化
export function setupPinia(app: App) {
const store = createPinia();
store.use(createPersistedState());
app.use(store);
}
+18
View File
@@ -0,0 +1,18 @@
import { defineStore } from "pinia";
import { useRoute } from "vue-router";
import { useRouter } from "vue-router";
export const useRouterStore = defineStore("router", () => {
const route = useRoute();
const router = useRouter();
const getCurrentPath = () => {
return route.path;
};
const toPath = (path: string) => {
router.push(path);
};
return {
getCurrentPath,
toPath,
};
});
+60
View File
@@ -0,0 +1,60 @@
import { ref, computed } from "vue";
import { defineStore } from "pinia";
const initState = {
id: "",
account: "",
email: "",
name: "",
token: "",
avatar: "",
};
export const useUserStore = defineStore(
"user",
() => {
const userInfo = ref<IUserInfo>({ ...initState });
const setUserInfo = (val: IUserInfo) => {
userInfo.value = { ...userInfo.value, ...val };
};
const clearUserInfo = () => {
reset();
};
// 一般没有reset需求,不需要的可以删除
const reset = () => {
userInfo.value = {
id: "",
account: "",
email: "",
name: "",
token: "",
avatar: "",
};
};
// ✅ 如果需要同时验证多个字段
const isLogined = computed(() => {
return !!(
(
userInfo.value.token && // 用户令牌
userInfo.value.id && // 用户ID
userInfo.value.account // 账户名
)
// userInfo.value.name // 名称
);
});
return {
userInfo,
setUserInfo,
clearUserInfo,
isLogined,
reset,
};
},
{
persist: true,
}
);
@@ -0,0 +1,328 @@
@charset "utf-8";
/* style */
.ys-panel,
.ys-panel-box {
padding: 0;
}
.ys-panel.active,
.ys-panel_hd {
padding: 10px;
}
.ys-panel-box.active {
margin: 0;
}
/* all */
body {
color: #333;
background: #fff;
}
/* text */
a,
h1,
h2,
h3,
h4,
h5,
h6,
h1 a,
h2 a,
h3 a,
h4 a,
h5 a,
h6 a {
color: #333;
}
a:hover {
color: cornflowerblue;
}
a.disabled {
cursor: not-allowed;
opacity: 0.6;
}
.text-333 {
color: #333;
}
.text-666 {
color: #666;
}
.text-muted {
color: #999;
}
.text-red {
color: red;
}
.text-link {
color: blue;
}
.text-fff {
color: #fff;
}
/* form */
.form-control {
color: #999999;
background-color: #f5f5f5;
border: 1px solid #eee;
}
.form-control:focus {
border-color: #ff9900;
-webkit-box-shadow:
inset 0 1px 1px rgba(255, 136, 0, 0.075),
0 0 8px rgba(255, 136, 0, 0.6);
}
/* btn */
.btn-default {
color: #333;
background: linear-gradient(to right, #eeeeee 0, #f6f6f6 100%);
background-color: #eee;
}
.btn-warm {
background: linear-gradient(to right, #ff9900 0, #ff9f16 100%);
background-color: #ff9900;
}
.btn-primary {
background: linear-gradient(to right, #4fb1f7 0, #6bb8ee 100%);
background-color: #4fb1f7;
}
.btn-danger {
background: linear-gradient(to right, #fc000c 0, #f9444d 100%);
background-color: #fc000c;
}
.btn-info {
background: linear-gradient(to right, #5bc0de 0, #7cc1d6 100%);
background-color: #5bc0de;
}
.btn-gray {
color: #ddd;
background: linear-gradient(to right, #282828 0, #3b3b3b 100%);
background-color: #282828;
}
.btn-warm,
.btn-primary,
.btn-danger,
.btn-info {
color: #fff;
}
.btn-warm:hover,
.btn-primary:hover,
.btn-danger:hover,
.btn-info:hover,
.btn-gray:hover {
color: #fff;
box-shadow: 0 5px 8px rgba(0, 0, 0, 0.1);
}
.btn.disabled {
cursor: not-allowed;
opacity: 0.6;
}
/* border */
.border {
border-color: #eee;
}
.border-primary {
border-color: #4fb1f7;
}
.border-danger {
border-color: red;
}
.border-info {
border-color: #5bc0de;
}
/* line */
.spot {
border-color: #ff9900;
}
.split-line {
background-color: #eee;
}
.top-line:before,
.bottom-line:after,
.top-line-dot:before,
.bottom-line-dot:before {
border-color: #eee;
}
/* badge */
.badge {
color: #333;
background-color: #eee;
}
.badge-first {
color: #fff;
background-color: #ff4a4a;
}
.badge-second {
color: #fff;
background-color: #ff7701;
}
.badge-third {
color: #fff;
background-color: #ffb400;
}
/* dropdown */
.dropdown-box .item {
background-color: #fff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
/* pic-tag */
.pic-tag .tag {
color: #fff;
background-color: rgba(0, 0, 0, 0.6);
}
.pic-tag .tag.active,
.pic-tag-h {
color: #fff;
background-color: #ff9900;
}
.pic-text,
.pic-title-bottom {
color: #fff;
background-image: linear-gradient(transparent, rgba(0, 0, 0, 0.5));
background-repeat: no-repeat;
}
.pic-text.active {
color: #fff;
background: rgba(0, 0, 0, 0.6);
}
.pic-title-top {
color: #fff;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0) 100%);
}
/* link */
.ys-link__pic li img {
display: block;
padding: 2px 6px;
background-color: #fff;
border-radius: 4px;
}
/* nav */
.nav-tabs > li.active a {
color: #ff9900;
border-color: #ff9900;
}
.nav-tabs > li .dropdown-box .item li a {
color: #333;
}
.nav-tabs > li .dropdown-box .item li.active a {
color: #ff9900;
}
.nav-btn > li a {
background-color: #f5f5f5;
}
.nav-btn > li.active a {
color: #fff;
background-color: #ff9900;
}
/* header */
.ys-header__top {
background-color: #fff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.ys-header__menu > li > a {
color: #333;
}
.ys-header__menu > li.active > a {
color: #ff9900;
}
.ys-header__search .form-control {
background-color: #f5f5f5;
}
.ys-header__user > li > a,
.ys-header__user > li > a .fa {
color: #333;
}
/* panel */
.ys-panel-bg {
background-color: #fff;
}
.ys-panel-bg2 {
background-color: #f5f5f5;
}
/* vodlist */
.ys-vodlist__bg {
background-color: #f5f5f5;
}
.ys-vodlist__bg:hover {
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.08);
}
/* text-list */
.ys-vodlist__text.striped .striped-head,
.ys-vodlist__text.to-color li:nth-of-type(odd) {
background-color: #f5f5f5;
}
/* table */
.ys-table > thead > tr > th,
.ys-table > tbody > tr > td,
.ys-table > tbody > tr > th,
.ys-table > tfoot > tr > td,
.ys-table > tfoot > tr > th,
.ys-table > thead > tr > td,
.ys-table > thead > tr > th {
border-color: #ddd;
}
/* player */
.ys-player__video {
background-color: #000;
}
.ys-player__operate > li > a {
color: #999;
}
/* popup */
.popup {
background-color: #f8f8f8;
}
.popup-head {
background-color: #fff;
}
/* content */
.ys-content__detail .score .rating li .fa,
.ys-content__detail .score .branch {
color: #ff9900;
}
/* flickity */
.flickity-page-dots .dot {
background-color: #ff9900;
}
/* carousel */
.carousel-indicators-dots li {
background-color: #ff9900;
}
.carousel-indicators-text li.active .title {
color: #ff9900;
}
.carousel-indicators-thumb li.active {
border: 3px solid #ff9900;
}
/* extra */
.ys-extra li a {
background-color: #fff;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
.ys-extra li a.backtop {
color: #fff;
background-color: rgba(0, 0, 0, 0.6);
}
/* autocomplete */
.autocomplete-suggestions {
background-color: #fff;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
}
.autocomplete-suggestion,
.autocomplete-suggestions li,
.autocomplete-suggestion,
.autocomplete-suggestions li a {
color: #333;
}
.autocomplete-suggestions li strong {
color: red;
}
/* tabbar */
.ys-nav__tabbar {
background-color: #f8f8f8;
border-color: #eee;
}
.ys-nav__tabbar .item .title {
color: #999;
}
/* footer */
.ys-foot {
background-color: #f8f8f8;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,6 @@
@import "./nprogress.css";
@import "./font.css";
@import "./color.css";
@import "./layer.css";
@import "./site.css";
@import "./ui.css";
@@ -0,0 +1,945 @@
.layui-layer-imgbar,
.layui-layer-imgtit a,
.layui-layer-tab .layui-layer-title span,
.layui-layer-title {
text-overflow: ellipsis;
white-space: nowrap;
}
html #layuicss-layer {
position: absolute;
display: none;
width: 1989px;
}
.layui-layer,
.layui-layer-shade {
position: fixed;
_position: absolute;
pointer-events: auto;
}
.layui-layer-shade {
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.layui-layer {
top: 150px;
left: 0;
padding: 0;
margin: 0;
background-color: #fff;
-webkit-background-clip: content;
border-radius: 2px;
box-shadow: 1px 1px 50px rgba(0, 0, 0, 0.3);
-webkit-overflow-scrolling: touch;
}
.layui-layer-close {
position: absolute;
}
.layui-layer-content {
position: relative;
}
.layui-layer-border {
border: 1px solid #b2b2b2;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);
}
.layui-layer-load {
background: url(loading-1.gif) center center no-repeat #eee;
}
.layui-layer-ico {
background: url(icon.png) no-repeat;
}
.layui-layer-btn a,
.layui-layer-dialog .layui-layer-ico,
.layui-layer-setwin a {
display: inline-block;
vertical-align: top;
}
.layui-layer-move {
position: fixed;
top: 0;
left: 0;
z-index: 2147483647;
display: none;
width: 100%;
height: 100%;
cursor: move;
background-color: #fff;
filter: alpha(opacity=0);
opacity: 0;
}
.layui-layer-resize {
position: absolute;
right: 0;
bottom: 0;
width: 15px;
height: 15px;
cursor: se-resize;
}
.layer-anim {
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
}
@-webkit-keyframes layer-bounceIn {
0% {
opacity: 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes layer-bounceIn {
0% {
opacity: 0;
-webkit-transform: scale(0.5);
-ms-transform: scale(0.5);
transform: scale(0.5);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
}
.layer-anim-00 {
-webkit-animation-name: layer-bounceIn;
animation-name: layer-bounceIn;
}
@-webkit-keyframes layer-zoomInDown {
0% {
opacity: 0;
-webkit-transform: scale(0.1) translateY(-2000px);
transform: scale(0.1) translateY(-2000px);
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
60% {
opacity: 1;
-webkit-transform: scale(0.475) translateY(60px);
transform: scale(0.475) translateY(60px);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
}
@keyframes layer-zoomInDown {
0% {
opacity: 0;
-webkit-transform: scale(0.1) translateY(-2000px);
-ms-transform: scale(0.1) translateY(-2000px);
transform: scale(0.1) translateY(-2000px);
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
60% {
opacity: 1;
-webkit-transform: scale(0.475) translateY(60px);
-ms-transform: scale(0.475) translateY(60px);
transform: scale(0.475) translateY(60px);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
}
.layer-anim-01 {
-webkit-animation-name: layer-zoomInDown;
animation-name: layer-zoomInDown;
}
@-webkit-keyframes layer-fadeInUpBig {
0% {
opacity: 0;
-webkit-transform: translateY(2000px);
transform: translateY(2000px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes layer-fadeInUpBig {
0% {
opacity: 0;
-webkit-transform: translateY(2000px);
-ms-transform: translateY(2000px);
transform: translateY(2000px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.layer-anim-02 {
-webkit-animation-name: layer-fadeInUpBig;
animation-name: layer-fadeInUpBig;
}
@-webkit-keyframes layer-zoomInLeft {
0% {
opacity: 0;
-webkit-transform: scale(0.1) translateX(-2000px);
transform: scale(0.1) translateX(-2000px);
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
60% {
opacity: 1;
-webkit-transform: scale(0.475) translateX(48px);
transform: scale(0.475) translateX(48px);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
}
@keyframes layer-zoomInLeft {
0% {
opacity: 0;
-webkit-transform: scale(0.1) translateX(-2000px);
-ms-transform: scale(0.1) translateX(-2000px);
transform: scale(0.1) translateX(-2000px);
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
60% {
opacity: 1;
-webkit-transform: scale(0.475) translateX(48px);
-ms-transform: scale(0.475) translateX(48px);
transform: scale(0.475) translateX(48px);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
}
.layer-anim-03 {
-webkit-animation-name: layer-zoomInLeft;
animation-name: layer-zoomInLeft;
}
@-webkit-keyframes layer-rollIn {
0% {
opacity: 0;
-webkit-transform: translateX(-100%) rotate(-120deg);
transform: translateX(-100%) rotate(-120deg);
}
100% {
opacity: 1;
-webkit-transform: translateX(0) rotate(0);
transform: translateX(0) rotate(0);
}
}
@keyframes layer-rollIn {
0% {
opacity: 0;
-webkit-transform: translateX(-100%) rotate(-120deg);
-ms-transform: translateX(-100%) rotate(-120deg);
transform: translateX(-100%) rotate(-120deg);
}
100% {
opacity: 1;
-webkit-transform: translateX(0) rotate(0);
-ms-transform: translateX(0) rotate(0);
transform: translateX(0) rotate(0);
}
}
.layer-anim-04 {
-webkit-animation-name: layer-rollIn;
animation-name: layer-rollIn;
}
@keyframes layer-fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.layer-anim-05 {
-webkit-animation-name: layer-fadeIn;
animation-name: layer-fadeIn;
}
@-webkit-keyframes layer-shake {
0%,
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translateX(-10px);
transform: translateX(-10px);
}
20%,
40%,
60%,
80% {
-webkit-transform: translateX(10px);
transform: translateX(10px);
}
}
@keyframes layer-shake {
0%,
100% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translateX(-10px);
-ms-transform: translateX(-10px);
transform: translateX(-10px);
}
20%,
40%,
60%,
80% {
-webkit-transform: translateX(10px);
-ms-transform: translateX(10px);
transform: translateX(10px);
}
}
.layer-anim-06 {
-webkit-animation-name: layer-shake;
animation-name: layer-shake;
}
@-webkit-keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.layui-layer-title {
height: 42px;
padding: 0 80px 0 20px;
overflow: hidden;
font-size: 14px;
line-height: 42px;
color: #333;
background-color: #f8f8f8;
border-bottom: 1px solid #eee;
border-radius: 2px 2px 0 0;
}
.layui-layer-setwin {
position: absolute;
top: 15px;
right: 15px;
font-size: 0;
line-height: initial;
}
.layui-layer-setwin a {
position: relative;
width: 16px;
height: 16px;
margin-left: 10px;
_overflow: hidden;
font-size: 12px;
}
.layui-layer-setwin .layui-layer-min cite {
position: absolute;
top: 50%;
left: 0;
width: 14px;
height: 2px;
margin-top: -1px;
_overflow: hidden;
cursor: pointer;
background-color: #2e2d3c;
}
.layui-layer-setwin .layui-layer-min:hover cite {
background-color: #2d93ca;
}
.layui-layer-setwin .layui-layer-max {
background-position: -32px -40px;
}
.layui-layer-setwin .layui-layer-max:hover {
background-position: -16px -40px;
}
.layui-layer-setwin .layui-layer-maxmin {
background-position: -65px -40px;
}
.layui-layer-setwin .layui-layer-maxmin:hover {
background-position: -49px -40px;
}
.layui-layer-setwin .layui-layer-close1 {
cursor: pointer;
background-position: 1px -40px;
}
.layui-layer-setwin .layui-layer-close1:hover {
opacity: 0.7;
}
.layui-layer-setwin .layui-layer-close2 {
position: absolute;
top: -28px;
_display: none;
width: 30px;
height: 30px;
margin-left: 0;
background-position: -149px -31px;
}
.layui-layer-setwin .layui-layer-close2:hover {
background-position: -180px -31px;
}
.layui-layer-btn {
padding: 0 15px 12px;
text-align: right;
pointer-events: auto;
-webkit-user-select: none;
user-select: none;
}
.layui-layer-btn a {
height: 28px;
padding: 0 15px;
margin: 5px 5px 0;
font-weight: 400;
line-height: 28px;
color: #333;
text-decoration: none;
cursor: pointer;
background-color: #fff;
border: 1px solid #dedede;
border-radius: 2px;
}
.layui-layer-btn a:hover {
text-decoration: none;
opacity: 0.9;
}
.layui-layer-btn a:active {
opacity: 0.8;
}
.layui-layer-btn .layui-layer-btn0 {
color: #fff;
background-color: #1e9fff;
border-color: #1e9fff;
}
.layui-layer-btn-l {
text-align: left;
}
.layui-layer-btn-c {
text-align: center;
}
.layui-layer-dialog {
min-width: 260px;
}
.layui-layer-dialog .layui-layer-content {
position: relative;
padding: 20px;
overflow: hidden;
overflow-x: hidden;
overflow-y: auto;
font-size: 14px;
line-height: 24px;
word-break: break-all;
}
.layui-layer-dialog .layui-layer-content .layui-layer-ico {
position: absolute;
top: 16px;
_left: -40px;
width: 30px;
height: 30px;
}
.layui-layer-ico1 {
background-position: -30px 0;
}
.layui-layer-ico2 {
background-position: -60px 0;
}
.layui-layer-ico3 {
background-position: -90px 0;
}
.layui-layer-ico4 {
background-position: -120px 0;
}
.layui-layer-ico5 {
background-position: -150px 0;
}
.layui-layer-ico6 {
background-position: -180px 0;
}
.layui-layer-rim {
border: 6px solid #8d8d8d;
border: 6px solid rgba(0, 0, 0, 0.3);
border-radius: 5px;
box-shadow: none;
}
.layui-layer-msg {
min-width: 180px;
border: 1px solid #d3d4d3;
box-shadow: none;
}
.layui-layer-hui {
min-width: 100px;
color: #fff;
background-color: #000;
background-color: rgba(0, 0, 0, 0.6);
filter: alpha(opacity=60);
border: none;
}
.layui-layer-hui .layui-layer-content {
padding: 12px 25px;
text-align: center;
}
.layui-layer-dialog .layui-layer-padding {
padding: 20px 20px 20px 55px;
text-align: left;
}
.layui-layer-page .layui-layer-content {
position: relative;
overflow: auto;
}
.layui-layer-iframe .layui-layer-btn,
.layui-layer-page .layui-layer-btn {
padding-top: 10px;
}
.layui-layer-nobg {
background: 0 0;
}
.layui-layer-iframe iframe {
display: block;
width: 100%;
}
.layui-layer-loading {
background: 0 0;
border: none;
border-radius: 100%;
box-shadow: none;
}
.layui-layer-loading .layui-layer-content {
width: 60px;
height: 24px;
background: url(loading-0.gif) no-repeat;
}
.layui-layer-loading .layui-layer-loading1 {
width: 37px;
height: 37px;
background: url(loading-1.gif) no-repeat;
}
.layui-layer-ico16,
.layui-layer-loading .layui-layer-loading2 {
width: 32px;
height: 32px;
background: url(loading-2.gif) no-repeat;
}
.layui-layer-tips {
background: 0 0;
border: none;
box-shadow: none;
}
.layui-layer-tips .layui-layer-content {
position: relative;
_float: left;
min-width: 12px;
padding: 8px 15px;
font-size: 12px;
line-height: 22px;
color: #fff;
background-color: #000;
border-radius: 2px;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
}
.layui-layer-tips .layui-layer-close {
top: -1px;
right: -2px;
}
.layui-layer-tips i.layui-layer-TipsG {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: dashed;
border-width: 8px;
}
.layui-layer-tips i.layui-layer-TipsB,
.layui-layer-tips i.layui-layer-TipsT {
left: 5px;
border-right-color: #000;
border-right-style: solid;
}
.layui-layer-tips i.layui-layer-TipsT {
bottom: -8px;
}
.layui-layer-tips i.layui-layer-TipsB {
top: -8px;
}
.layui-layer-tips i.layui-layer-TipsL,
.layui-layer-tips i.layui-layer-TipsR {
top: 5px;
border-bottom-color: #000;
border-bottom-style: solid;
}
.layui-layer-tips i.layui-layer-TipsR {
left: -8px;
}
.layui-layer-tips i.layui-layer-TipsL {
right: -8px;
}
.layui-layer-lan[type="dialog"] {
min-width: 280px;
}
.layui-layer-lan .layui-layer-title {
color: #fff;
background: #4476a7;
border: none;
}
.layui-layer-lan .layui-layer-btn {
padding: 5px 10px 10px;
text-align: right;
border-top: 1px solid #e9e7e7;
}
.layui-layer-lan .layui-layer-btn a {
color: #333;
background: #fff;
border-color: #e9e7e7;
}
.layui-layer-lan .layui-layer-btn .layui-layer-btn1 {
background: #c9c5c5;
}
.layui-layer-molv .layui-layer-title {
color: #fff;
background: #009f95;
border: none;
}
.layui-layer-molv .layui-layer-btn a {
background: #009f95;
border-color: #009f95;
}
.layui-layer-molv .layui-layer-btn .layui-layer-btn1 {
background: #92b8b1;
}
.layui-layer-iconext {
background: url(icon-ext.png) no-repeat;
}
.layui-layer-prompt .layui-layer-input {
display: block;
width: 230px;
height: 36px;
padding-left: 10px;
margin: 0 auto;
line-height: 30px;
color: #333;
border: 1px solid #e6e6e6;
}
.layui-layer-prompt textarea.layui-layer-input {
width: 300px;
height: 100px;
padding: 6px 10px;
line-height: 20px;
}
.layui-layer-prompt .layui-layer-content {
padding: 20px;
}
.layui-layer-prompt .layui-layer-btn {
padding-top: 0;
}
.layui-layer-tab {
box-shadow: 1px 1px 50px rgba(0, 0, 0, 0.4);
}
.layui-layer-tab .layui-layer-title {
padding-left: 0;
overflow: visible;
}
.layui-layer-tab .layui-layer-title span {
position: relative;
float: left;
min-width: 80px;
max-width: 260px;
padding: 0 20px;
overflow: hidden;
text-align: center;
cursor: pointer;
}
.layui-layer-tab .layui-layer-title span.layui-this {
z-index: 10;
height: 43px;
background-color: #fff;
border-right: 1px solid #eee;
border-left: 1px solid #eee;
}
.layui-layer-tab .layui-layer-title span:first-child {
border-left: none;
}
.layui-layer-tabmain {
clear: both;
line-height: 24px;
}
.layui-layer-tabmain .layui-layer-tabli {
display: none;
}
.layui-layer-tabmain .layui-layer-tabli.layui-this {
display: block;
}
.layui-layer-photos {
-webkit-animation-duration: 0.8s;
animation-duration: 0.8s;
}
.layui-layer-photos .layui-layer-content {
overflow: hidden;
text-align: center;
}
.layui-layer-photos .layui-layer-phimg img {
position: relative;
display: inline-block;
width: 100%;
vertical-align: top;
}
.layui-layer-imgbar,
.layui-layer-imguide {
display: none;
}
.layui-layer-imgnext,
.layui-layer-imgprev {
position: absolute;
top: 50%;
_width: 44px;
height: 44px;
margin-top: -22px;
outline: 0;
}
.layui-layer-imgprev {
left: 10px;
_background-position: -70px -5px;
}
.layui-layer-imgprev:hover {
_background-position: -120px -5px;
}
.layui-layer-imgnext {
_right: 8px;
_background-position: -70px -50px;
}
.layui-layer-imgnext:hover {
_background-position: -120px -50px;
}
.layui-layer-imgbar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 32px;
overflow: hidden;
font-size: 0;
line-height: 32px;
color: #fff;
background-color: rgba(0, 0, 0, 0.8);
filter: Alpha(opacity=80);
}
.layui-layer-imgtit * {
display: inline-block;
font-size: 12px;
vertical-align: top;
}
.layui-layer-imgtit a {
max-width: 65%;
overflow: hidden;
color: #fff;
}
.layui-layer-imgtit a:hover {
color: #fff;
text-decoration: underline;
}
.layui-layer-imgtit em {
padding-left: 10px;
font-style: normal;
}
@-webkit-keyframes layer-bounceOut {
100% {
opacity: 0;
-webkit-transform: scale(0.7);
transform: scale(0.7);
}
30% {
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes layer-bounceOut {
100% {
opacity: 0;
-webkit-transform: scale(0.7);
-ms-transform: scale(0.7);
transform: scale(0.7);
}
30% {
-webkit-transform: scale(1.05);
-ms-transform: scale(1.05);
transform: scale(1.05);
}
0% {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
}
.layer-anim-close {
-webkit-animation-name: layer-bounceOut;
animation-name: layer-bounceOut;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-duration: 0.2s;
animation-duration: 0.2s;
}
@media screen and (max-width: 1100px) {
.layui-layer-iframe {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
}
@@ -0,0 +1,65 @@
/* Make clicks pass-through */
#nprogress {
pointer-events: none;
}
/* Remove the shadow effect */
#nprogress .peg {
position: absolute;
right: 0px;
display: block;
width: 100px;
height: 100%;
opacity: 1;
-webkit-transform: rotate(3deg) translate(0px, -4px);
-ms-transform: rotate(3deg) translate(0px, -4px);
transform: rotate(3deg) translate(0px, -4px);
}
/* Remove spinner and its shadow */
#nprogress .spinner {
position: fixed;
top: 15px;
right: 15px;
z-index: 1031;
display: block;
}
#nprogress .spinner-icon {
box-sizing: border-box;
width: 18px;
height: 18px;
border: solid 2px transparent;
border-top-color: #646cff;
border-left-color: #646cff;
border-radius: 50%;
box-shadow: none; /* Remove spinner shadow */
-webkit-animation: nprogress-spinner 300ms linear infinite;
animation: nprogress-spinner 300ms linear infinite;
}
.nprogress-custom-parent {
position: relative;
overflow: hidden;
}
.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);
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,4 @@
// 通过完整层级穿透确保命中
:deep(.arco-badge-dot) {
box-shadow: 0 0 0 0;
}
+15
View File
@@ -0,0 +1,15 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AButton: typeof import('@arco-design/web-vue')['Button']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SvgIcon: typeof import('./../components/svg-icon.vue')['default']
}
}
+12
View File
@@ -0,0 +1,12 @@
export enum ResponseStatusEnum {
SUCCESS = 200,
ERROR = 500,
UNAUTHORIZED = 401,
RESOURCE_CREATED_SUCCESS = 201,
RESOURCE_CREATED_ERROR = 409,
}
export enum ResponseStatusErrorMessageEnum {
NO_LOGIN = "尚未登录,请先登录!",
}
+13
View File
@@ -0,0 +1,13 @@
// src/env.d.ts
declare namespace Env {
interface ImportMeta extends ImportMetaEnv {
readonly VITE_BASE_URL: string;
readonly VITE_APP_TITLE: string;
readonly VITE_ICON_PREFIX: string;
readonly VITE_ICON_LOCAL_PREFIX: string;
readonly VITE_SERVER_BASEURL: string;
readonly VITE_UPLOAD_BASEURL: string;
readonly VITE_APP_PROXY: string;
readonly VITE_APP_PROXY_PREFIX: string;
}
}
+29
View File
@@ -0,0 +1,29 @@
import { AdminStatusEnum } from "@/types/enums"
declare global {
interface Window {
/** NProgress instance */
NProgress?: import("nprogress").NProgress
// $message?: import("@arco-design/web-vue/es/Message/interface").MessageMethod;
}
/** Build time of the project */
const BUILD_TIME: string
type IUserInfo = {
id: string
account?: string
email?: string
name?: string
token?: string
avatar?: string
}
type IResData<T = unknown> = {
code: number
message: string
data: T
}
}
export {} // 确保 TypeScript 将此文件视为模块,防止全局污染
+9
View File
@@ -0,0 +1,9 @@
interface BasePageParams {
page: number;
pageSize: number;
}
interface BasePageResult<T> {
total: number; // 总条数
record: T[]; // 当前页数据列表
}
@@ -0,0 +1,16 @@
export function toJson(obj: any): string {
try {
return JSON.stringify(obj);
} catch (error) {
console.error("JSON 转换失败", error);
return "";
}
}
export function toObject<T>(json: string): T | null {
try {
return JSON.parse(json) as T;
} catch (error) {
console.error("JSON 解析失败", error);
return null;
}
}
+157
View File
@@ -0,0 +1,157 @@
import { getAliyunKeyApi, insertFileApi } from "@/service/file";
import { Message } from "@arco-design/web-vue";
export interface UploadImageResponse {
name: string;
size: string;
url: string;
blob: Blob;
}
export const uploadImage = (
options: {
quality?: number;
mimeType?: string;
} = {}
): Promise<UploadImageResponse> => {
const { quality = 0.8, mimeType = "image/webp" } = options;
return new Promise((resolve, reject) => {
if (typeof document === "undefined") {
reject(new Error("Require browser environment"));
return;
}
const input = document.createElement("input");
input.type = "file";
input.accept = "image/*";
input.style.display = "none";
const processImage = (file: File): Promise<UploadImageResponse> => {
return new Promise((resolve, reject) => {
const img = new Image();
const objectURL = URL.createObjectURL(file);
img.onload = () => {
try {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) throw new Error("Canvas init failed");
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
URL.revokeObjectURL(objectURL);
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error("Compression failed"));
return;
}
resolve({ name: file.name, size: blob.size.toString(), url: URL.createObjectURL(blob), blob: blob });
},
mimeType,
quality
);
} catch (error) {
reject(error);
}
};
img.onerror = () => {
URL.revokeObjectURL(objectURL);
reject(new Error("Image load failed"));
};
img.src = objectURL;
});
};
input.onchange = async (event) => {
const file = (event.target as HTMLInputElement).files?.[0];
if (!file) {
reject(new Error("No file selected"));
return;
}
try {
if (!file.type.startsWith("image/")) {
throw new Error("Invalid image file");
}
const result = await processImage(file);
resolve(result);
} catch (error) {
reject(error);
} finally {
document.body.removeChild(input);
}
};
document.body.appendChild(input);
input.click();
});
};
export interface UploadToAliyunResponse {
url: string;
fileName: string;
fileSize: string;
}
export function uploadToAliyun(blob: Blob, fileName: string, fileSize: string): Promise<UploadToAliyunResponse> {
return new Promise((resolve, reject) => {
getAliyunKeyApi()
.then(async (res) => {
try {
const aliyunKey = res.data;
const formData = new FormData();
// 生成唯一文件名(保留原始后缀)
const fileExt = fileName.includes(".") ? fileName.slice(fileName.lastIndexOf(".")) : "";
const uniqueName = `sl_${Date.now()}_${Math.random().toString(36).slice(2)}${fileExt}`;
// 构造表单数据
formData.append("key", `${aliyunKey.dir}${uniqueName}`);
formData.append("OSSAccessKeyId", aliyunKey.accessid);
formData.append("policy", aliyunKey.policy);
formData.append("Signature", aliyunKey.signature);
formData.append("file", blob, uniqueName);
// 执行上传
const response = await fetch(aliyunKey.host, {
method: "POST",
body: formData
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`OSS响应错误: ${errorText}`);
}
// 获取完整文件路径
const allFilePath = `${aliyunKey.host}/${aliyunKey.dir}${uniqueName}`;
// 调用插入记录接口
await insertFileApi({
fileName,
fileSize,
fileMapName: allFilePath
});
// 返回标准化结果
resolve({
url: allFilePath,
fileName,
fileSize
});
} catch (error) {
Message.error("文件上传流程失败");
reject(error);
}
})
.catch(reject); // 捕获获取凭证失败的错误
});
}
+21
View File
@@ -0,0 +1,21 @@
import axiosInstance from "@/interceptors/http";
export function httpGet<T>(url: string, params?: Record<string, any>): Promise<IResData<T>> {
return axiosInstance.get(url, { params });
}
export function httpPostJson<T>(url: string, data?: Record<string, any>): Promise<IResData<T>> {
return axiosInstance.post(url, data, {
headers: {
"Content-Type": "application/json"
}
});
}
export function httpPostForm<T>(url: string, data?: any): Promise<IResData<T>> {
return axiosInstance.post(url, data, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
});
}
+26
View File
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"target": "ESNext",
"jsx": "preserve",
"jsxImportSource": "vue",
"lib": ["DOM", "ESNext"],
"baseUrl": ".",
"module": "ESNext",
"moduleResolution": "node",
"paths": {
"@/*": ["./src/*"],
"~/*": ["./*"]
},
"resolveJsonModule": true,
"types": ["vite/client", "node", "unplugin-icons/types/vue"],
"strict": true,
"strictNullChecks": true,
"noUnusedLocals": false,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true
},
"include": ["./**/*.ts", "./**/*.tsx", "./**/*.vue"],
"exclude": ["node_modules", "dist"]
}
+17
View File
@@ -0,0 +1,17 @@
import { defineConfig } from "@unocss/vite";
import transformerDirectives from "@unocss/transformer-directives";
import transformerVariantGroup from "@unocss/transformer-variant-group";
import presetUno from "@unocss/preset-uno";
import type { Theme } from "@unocss/preset-uno";
export default defineConfig<Theme>({
content: {
pipeline: {
exclude: ["node_modules", "dist"]
}
},
rules: [],
theme: {},
shortcuts: {},
transformers: [transformerDirectives(), transformerVariantGroup()],
presets: [presetUno({ dark: "class" })]
});
+59
View File
@@ -0,0 +1,59 @@
import { URL, fileURLToPath } from "node:url";
import process from "node:process";
import { defineConfig, loadEnv } from "vite";
import { setupVitePlugins } from "./build/plugins/index";
import { getBuildTime } from "./build/config";
export default defineConfig((configEnv) => {
const viteEnv = loadEnv(configEnv.mode, process.cwd()) as unknown as Env.ImportMeta;
const { VITE_SERVER_BASEURL, VITE_APP_PROXY, VITE_APP_PROXY_PREFIX } = viteEnv;
const buildTime = getBuildTime();
return {
base: viteEnv.VITE_BASE_URL,
resolve: {
// 使其通过能 ~ 或 @ 导入
alias: {
"~": fileURLToPath(new URL("./", import.meta.url)),
"@": fileURLToPath(new URL("./src", import.meta.url))
}
},
css: {
preprocessorOptions: {
scss: {
api: "modern-compiler",
additionalData: `@use "@/styles/scss/global.scss" as *;`
}
}
},
plugins: setupVitePlugins(viteEnv, buildTime),
//
define: {
BUILD_TIME: JSON.stringify(buildTime)
},
server: {
host: "0.0.0.0",
port: 8080,
open: true,
// 用于配置开发服务器启动时预加载的一些客户端文件,以提高初次加载的速度。
warmup: {
clientFiles: ["./index.html", "./src/{pages,components}/*"]
},
proxy:
VITE_APP_PROXY === "Y"
? {
[VITE_APP_PROXY_PREFIX]: {
target: VITE_SERVER_BASEURL,
changeOrigin: true, // 跨域
rewrite: (path) => path.replace(/^\/api/, "") //路径重写,把'/api'替换为''
// rewrite: (path) => path.replace(new RegExp(`^${VITE_APP_PROXY_PREFIX}`), "")
}
}
: undefined
},
// 用于生产环境,可以使用vite preview预览构建后的应用 pnpm run preview
preview: {
port: 9725
}
};
});