This commit is contained in:
2023-11-07 17:15:33 +08:00
commit fe37e2e1df
418 changed files with 53012 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
<template>
<view class="mini-none">
<view style="display: flex;">
<view
v-for="(item, index) in vk.getVuex('$app.menuMap')"
:key="index"
@click="pageTo(item)"
class="top-bar"
>
<view class="item-content" v-if="item.name">
{{ item.name }}
<text v-if="index !== vk.getVuex('$app.menuMap').length - 1" class="item-content-text">
/
</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {},
data: function() {
// 组件创建时,进行数据初始化
return {};
},
mounted() {},
methods: {
pageTo(item={}){
let { vk } = this;
if(item.url){
vk.navigateTo(item.url);
}
}
},
watch: {},
// 过滤器
filters: {},
// 计算属性
computed: {}
};
</script>
<style lang="scss" scoped>
.top-bar {
margin-left: 10px;
cursor: pointer;
}
.top-bar:first-child {
margin-left: 0px;
}
.item-content {
color: #606266;
}
.item-content:hover {
color: #409eff;
}
.item-content-text {
margin-left: 10px;
color: #a3a9a9;
font-weight: bold;
}
</style>
+145
View File
@@ -0,0 +1,145 @@
<template>
<vk-data-dialog
v-model="value.show"
:title="page.title"
:top="page.top"
:width="page.width"
mode="form"
>
<view class="page-body">
<!-- 自定义按钮区域开始 -->
<view class="btns-box">
<el-row>
<el-button size="small" icon="el-icon-delete" @click="clearErrorLog">清空日志</el-button>
</el-row>
</view>
<!-- 自定义按钮区域结束 -->
<!-- 表格组件开始 -->
<vk-data-table
ref="table1"
:data="vk.getVuex('$error.logs')"
:columns="table1.columns"
:row-no="true"
:height="600"
:custom-right-btns="[
{
title: '百度',
icon: 'el-icon-document'
},
{
title: '谷歌',
icon: 'el-icon-document'
}
]"
@custom-right-btns="customRightBtns"
></vk-data-table>
<!-- 表格组件结束 -->
</view>
</vk-data-dialog>
</template>
<script>
var that; // 当前页面对象
var vk; // vk实例
export default {
props: {
value: {
Type: Object,
default: function() {
return {
show: false,
mode: "",
item: ""
};
}
}
},
data: function() {
// 组件创建时,进行数据初始化
return {
page: {
title: "错误日志",
top: "7vh",
width: "1250px"
},
table1: {
show: false,
columns: [
{ key: "info", title: "类型", type: "text", width: 160 },
{ key: "route", title: "页面地址", type: "text", width: 240 },
{ key: "err", title: "错误信息", type: "text", minWidth: 260 },
{ key: "time", title: "距离现在", type: "dateDiff", width: 120 },
{ key: "timeStr", title: "发生时间", type: "text", width: 120 }
]
}
};
},
mounted() {
that = this;
vk = that.vk;
that.init();
},
methods: {
// 初始化
init() {
let { value } = that;
that._input(value);
},
_input(value) {
that.$emit("input", value);
},
// 清除错误日志
clearErrorLog() {
let that = this;
let { vk } = that;
vk.vuex.dispatch("$error/clear");
that.close();
},
// 错误日志表格的右侧自定义按钮点击事件
customRightBtns(row, btn) {
if (btn.title === "百度") {
window.open(`https://www.baidu.com/baidu?wd=${row.err}`);
} else if (btn.title === "谷歌") {
window.open(`https://www.google.com/search?q=${row.err}`);
}
},
// 监听 - 页面打开
onOpen() {
that = this;
},
// 监听 - 页面关闭
onClose() {},
// 打开页面
open() {
let { value } = that;
value.show = true;
that._input(value);
},
// 关闭页面
close() {
let { value } = that;
value.show = false;
that._input(value);
}
},
watch: {
"value.show": {
handler(newValue, oldValue) {
let that = this;
if (newValue) {
that.onOpen();
} else {
that.onClose();
}
}
}
},
// 过滤器
filters: {},
// 计算属性
computed: {}
};
</script>
<style lang="scss" scoped></style>
+175
View File
@@ -0,0 +1,175 @@
<template>
<vk-data-dialog
v-model="value.show"
:title="page.title"
:top="page.top"
:width="page.width"
mode="form"
>
<!-- 页面主体内容开始 -->
<vk-data-form
ref="form1"
v-model="form1.data"
:form-type="value.mode"
:rules="form1.props.rules"
:action="form1.props.action"
:columns="form1.props.columns"
:loading.sync="form1.props.loading"
:labelWidth="form1.props.labelWidth"
:before-action="form1.props.beforeAction"
:show-cancel="page.showCancel"
:cancel-text="page.cancelText"
:submit-text="page.submitText"
@success="onFormSuccess"
></vk-data-form>
<!-- 页面主体内容结束 -->
</vk-data-dialog>
</template>
<script>
var that; // 当前页面对象
var vk; // vk实例
export default {
props: {
value: {
Type: Object,
default: function() {
return {
show: false,
mode: "",
item: ""
};
}
}
},
data: function() {
// 组件创建时,进行数据初始化
return {
page: {
title: "修改密码",
submitText: "修改",
cancelText: "关闭",
showCancel: true,
top: "14vh",
width:"500px"
},
form1: {
// 表单请求数据,此处可以设置默认值
data: {
},
// 表单属性
props: {
// 表单请求地址
action: "user/kh/updatePwd",
// 表单字段显示规则
columns: [
{ key: "username", title: "账号", type: "text", disabled:true },
{ key: "oldPassword", title: "原密码", type: "password" },
{ key: "newPassword", title: "新密码", type: "password" },
{ key: "newPassword2", title: "确认新密码", type: "password" },
],
// 表单验证规则
rules: {
oldPassword:[
{ required:true, message:'原密码不能为空', trigger:'change' },
{ validator:uni.vk.pubfn.validator("pwd"), message: '密码长度在6~18之间,只能包含字母、数字和下划线', trigger: 'change' }
],
newPassword:[
{ required:true, message:'新密码不能为空', trigger:'change' },
{ validator:uni.vk.pubfn.validator("pwd"), message: '密码长度在6~18之间,只能包含字母、数字和下划线', trigger: 'change' }
],
newPassword2:[
{ required:true, message:'请再次输入新密码', trigger:'change' },
{ validator:uni.vk.pubfn.validator("pwd"), message: '密码长度在6~18之间,只能包含字母、数字和下划线', trigger: 'change' }
],
},
labelWidth: "100px",
beforeAction:function(data){
if(data.newPassword !== data.newPassword2){
vk.toast("两次密码不一样,请检查!","none");
return false;
}
}
}
}
};
},
mounted() {
that = this;
vk = that.vk;
that.init();
},
methods: {
// 初始化
init() {
let { value } = that;
that._input(value);
},
_input(value){
that.$emit("input", value);
},
// 监听 - 页面打开
onOpen() {
that = this;
let { value={} } = that;
let { item } = value;
let userInfo = vk.getVuex("$user.userInfo");
that.form1.data.username = userInfo.username;
},
// 监听 - 页面关闭
onClose() {
that.resetForm();
},
// 监听 - 提交成功后
onFormSuccess() {
that.close();
that.$emit("success");
},
// 打开页面
open() {
let { value } = that;
value.show = true;
that._input(value);
},
// 关闭页面
close() {
let { value } = that;
value.show = false;
that._input(value);
},
// 表单重置
resetForm() {
that.$refs.form1.resetForm();
},
// 表单提交
submitForm() {
that.$refs.form1.submitForm();
}
},
watch: {
"value.show": {
handler(newValue, oldValue) {
let that = this;
if (newValue) {
that.onOpen();
} else {
that.onClose();
}
}
}
},
// 过滤器
filters: {
},
// 计算属性
computed: {
}
};
</script>
<style lang="scss" scoped>
</style>
+90
View File
@@ -0,0 +1,90 @@
<template>
<scroll-view class="sidebar" :class="classCom" scroll-y="true" v-loading="!vk.getVuex('$app.inited')" :style="styleCom">
<vk-data-menu-nav
v-if="vk.getVuex('$app.inited')"
:data="vk.getVuex('$app.navMenu')"
:unique-opened="true"
:collapse="vk.getVuex('$app.leftCollapse')"
:collapse-transition="false"
:theme="theme"
default-menu-icon="el-icon-folder-opened"
default-sub-menu-icon="el-icon-tickets"
@select="select"
></vk-data-menu-nav>
</scroll-view>
</template>
<script>
import config from "@/app.config.js";
export default {
data() {
return {
theme: config.theme
}
},
methods: {
select(e){
},
},
// 监听属性
watch: {
$route: {
immediate: true,
handler(newRoute, oldRoute) {
let that = this;
let { vk } = that;
let { path , query } = newRoute;
let url = path + vk.pubfn.queryParams(query);
let route = { path, query, url };
vk.setVuex('$app.route', route);
}
}
},
// 计算属性
computed: {
styleCom(){
let theme = this.theme;
if (theme && theme.use) {
return theme[theme.use].leftMenu;
} else {
return {};
}
},
classCom(){
let obj = {
pc: vk.getVuex('$app.isPC'),
mobile: !vk.getVuex('$app.isPC'),
collapse: vk.getVuex('$app.leftCollapse'),
};
return obj;
}
}
}
</script>
<style lang="scss">
.sidebar {
position: fixed;
top: var(--window-top);
width: 240px;
height: calc(100vh - (var(--window-top)) + 50px);
box-sizing: border-box;
box-shadow: var(--boxShadow, 2px 0 0px rgba(0,21,4,0.2));
border-top: var(--borderTop);
background-color: $left-window-bg-color;
padding-bottom: 10px;
top: 50px;
z-index: 998;
}
.sidebar.collapse{
width: 64px;
}
.title {
margin-left: 5px;
}
.center{
text-align: center;
margin-top: 100px;
}
</style>
+518
View File
@@ -0,0 +1,518 @@
<template>
<view class="header no-user-select" v-loading="!vk.getVuex('$app.inited')" :style="'--textColor'+textColor">
<!-- 左侧 -->
<view class="left">
<!-- 模式一:纯图片 -->
<navigator class="logo-mode-1" open-type="reLaunch" url="/">
<image :src="vk.getVuex('$app.staticUrl.navBar.logo1')" mode="aspectFill" class="logo-image" v-show="vk.getVuex('$app.leftCollapse')"></image>
<image :src="vk.getVuex('$app.staticUrl.navBar.logo2')" mode="aspectFill" class="logo-image" v-show="!vk.getVuex('$app.leftCollapse')"></image>
</navigator>
<!-- 模式二:图片+文字 -->
<!-- <navigator class="logo-mode-2" open-type="reLaunch" url="/">
<view class="logo-box" v-show="!vk.getVuex('$app.leftCollapse')">
<image class="logo-image" :src="vk.getVuex('$app.staticUrl.navBar.logo')" mode="scaleToFill"></image>
<view class="app-name">vk-admin后台管理</view>
</view>
<view class="logo-box" v-show="vk.getVuex('$app.leftCollapse')">
<image class="logo-image" :src="vk.getVuex('$app.staticUrl.navBar.logo')" mode="aspectFit"></image>
</view>
</navigator> -->
</view>
<!-- 右侧 -->
<view class="right">
<!-- 右上 -->
<view class="right-top" :style="topMenuStyle">
<view
class="navbar"
:class="{ 'navbar-mini': !matchLeftWindow, 'popup-menu': popupMenuOpened }"
>
<vk-data-icon
class="menu-collapse"
:name="vk.getVuex('$app.leftCollapse') ? 'vk-icon-zhankaicaidan':'vk-icon-shouqicaidan'"
size="17"
:color="textColor"
:pointer="true"
@click="menuCollapse"
></vk-data-icon>
<!-- 面包屑 -->
<breadcrumb></breadcrumb>
<view class="navbar-left pointer">
<vk-data-icon
@click="toggleSidebar"
class="menu-icon"
name="vk-icon-sortlight"
size="30"
:color="textColor"
></vk-data-icon>
</view>
<view class="navbar-middle">
<text class="title-text">{{ navigationBarTitleText }}</text>
</view>
<view class="navbar-right pointer">
<view
@click="togglePopupMenu"
class="navbar-user"
>
<view class="username">
<text>{{ vk.getVuex("$user.userInfo.username") }}</text>
</view>
<vk-data-icon
class="arrowdown"
name="vk-icon-unfold"
:color="textColor"
size="13"
></vk-data-icon>
</view>
<view class="vk-mask" @click="togglePopupMenu"></view>
<view class="navbar-menu">
<!-- #ifdef H5 -->
<view
v-if="vk.getVuex('$error.logs').length"
@click="openForm('errorLog')"
class="menu-item debug pointer"
>
<el-badge :value="vk.getVuex('$error.logs').length" class="item">
<vk-data-icon
name="el-icon-message-solid"
size="22"
:color="textColor"
></vk-data-icon>
</el-badge>
</view>
<!-- #endif -->
<view
v-if="vk.getVuex('$app.width') >= 1100 && debug"
v-for="link in links"
:key="link.url"
class="menu-item text-overflow"
>
<vk-data-link :href="link.url" :text="link.text" />
</view>
<view class="menu-item text-overflow">
<text>{{ vk.getVuex("$user.userInfo.username") }}</text>
</view>
<view class="menu-item" @click="openForm('updatePassword')">
<text class="text-overflow">修改密码</text>
</view>
<view class="menu-item">
<text class="logout pointer text-overflow" @click="logout">退出</text>
</view>
<view class="popup-menu__arrow"></view>
</view>
</view>
</view>
</view>
<!-- 右下 -->
<view class="right-bottom">
<!-- tabs标签组 -->
<vk-data-menu-tabs v-if="vk.getVuex('$app.inited')" ref="menuTabs"></vk-data-menu-tabs>
</view>
</view>
<!-- 弹窗 - 错误日志 -->
<errorLog v-model="formDatas.errorLog"></errorLog>
<!-- 弹窗 - 修改密码 -->
<updatePassword v-model="formDatas.updatePassword"></updatePassword>
</view>
</template>
<script>
import config from "@/app.config.js";
import breadcrumb from "./components/breadcrumb";
import errorLog from "./components/errorLog";
import updatePassword from "./components/updatePassword";
export default {
components: {
breadcrumb,
errorLog,
updatePassword
},
props: {
navigationBarTitleText: {
type: String
},
matchLeftWindow: {
type: Boolean
},
showLeftWindow: {
type: Boolean
}
},
data() {
return {
debug: config.debug,
// 主题配置
theme: config.theme,
// 右侧链接,只在开发模式时显示
links: [
{
text: "Admin框架文档",
url: "https://vkdoc.fsq.pub/admin/"
},
{
text: "浏览更多VK插件",
url: "https://ext.dcloud.net.cn/search?q=vk"
}
],
popupMenuOpened: false,
tabCheck: "",
formDatas: {}
};
},
// 组件挂载完毕时
mounted() {
this.vk.menuTabs = this.$refs.menuTabs;
this.checkMenuCollapse();
},
methods: {
// 退出登录
logout() {
let that = this;
let { vk } = that;
vk.userCenter.logout({
success: function(data) {
if (typeof that.$refs.menuTabs.clear === "function") that.$refs.menuTabs.clear();
uni.reLaunch({
url: config.login.url
});
}
});
},
// 左侧菜单显示和隐藏
toggleSidebar() {
let that = this;
if (!that.showLeftWindow) {
uni.showLeftWindow();
} else {
uni.hideLeftWindow();
}
},
// 右上方菜单显示和隐藏
togglePopupMenu() {
let that = this;
that.popupMenuOpened = !that.popupMenuOpened;
},
// 打开表单
openForm(name) {
let that = this;
let { vk } = that;
that.formDatas[name] = {
show: true
};
},
// pc状态下菜单折叠
menuCollapse(){
let leftCollapse = vk.getVuex('$app.leftCollapse');
vk.setVuex('$app.leftCollapse', !leftCollapse);
this.checkMenuCollapse();
},
checkMenuCollapse(){
let leftCollapse = vk.getVuex('$app.leftCollapse');
if (!leftCollapse) {
// 打开
uni.setLeftWindowStyle({
width: '240px',
});
} else {
// 折叠
uni.setLeftWindowStyle({
width: '64px',
});
}
}
},
// 计算属性
computed: {
topMenuStyle(){
let theme = this.theme;
if (theme && theme.use) {
let topMenu = theme[theme.use].topMenu;
let {
backgroundColor,
textColor
} = topMenu;
return {
backgroundColor,
color:textColor
}
} else {
return {}
}
},
textColor(){
let theme = this.theme;
if (theme && theme.use) {
return theme[theme.use].topMenu.textColor || "#999";
} else {
return "#999";
}
}
}
};
</script>
<style lang="scss">
.header {
height: 100px;
width: 100%;
box-sizing: border-box;
display: flex;
border-bottom: 1px solid darken($top-window-bg-color, 3%);
background-color: $top-window-bg-color;
color: $top-window-text-color;
/* 左侧 */
.left {
width: calc(var(--window-left));
}
/* 右侧 */
.right {
width: calc(100% - var(--window-left));
.navbar {
font-size: 13px;
position: relative;
height: 100%;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.menu-icon {
width: 30px;
height: 30px;
line-height: 30px;
}
.menu-collapse{
width: 30px;
height: 30px;
line-height: 30px;
}
.navbar-left,
.navbar-middle,
.navbar-right {
flex: 1;
}
.navbar-middle,
.username {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.navbar-middle {
text-align: center;
}
.username {
max-width: 150px;
}
.text-overflow {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.text-overflow {
max-width: 150px;
}
.title-text {
font-size: 13px;
line-height: 30px;
}
.navbar-menu {
display: flex;
}
.menu-item {
padding: 5px;
}
.debug {
display: inline-block;
position: relative;
}
.debug-badge {
position: absolute;
top: 5px;
right: 13px;
transform: translateY(-50%) translateX(100%) scale(0.8);
}
.arrowdown {
margin-top: 4px;
margin-left: 3px;
}
.navbar-right {
display: flex;
justify-content: flex-end;
}
.navbar-right .vk-mask {
background-color: rgba(255, 255, 255, 0);
}
.popup-menu__arrow {
position: absolute;
top: -6px;
right: 20px;
border-width: 6px;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #ebeef5;
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
}
.popup-menu__arrow::after {
content: " ";
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
/* 大屏时,隐藏的内容 */
.menu-icon,
.navbar-middle,
.navbar-user,
.popup-menu__arrow,
.navbar-right .vk-mask {
display: none;
}
/* 小屏,显示的内容 */
.navbar-mini .menu-icon,
.navbar-mini .navbar-middle {
display: block;
}
.navbar-mini .navbar-user {
display: flex;
}
/* 小屏时,隐藏的内容 */
.navbar-mini .menu-collapse,
.navbar-mini .logo,
.navbar-mini .debug,
.navbar-mini .navbar-menu,
.navbar-mini .navbar-menu .username,
.navbar-mini .breadcrumb-view,
.navbar-mini .mini-none {
display: none;
}
.navbar-mini .navbar-menu {
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
right: 20px;
top: 50px;
background-color: #fff;
z-index: 999;
padding: 0px 15px;
margin: 5px 0;
background-color: #fff;
border: 1px solid #ebeef5;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
/* 小屏时,弹出下拉菜单 */
.navbar-mini.popup-menu .navbar-menu {
display: flex;
}
.navbar-mini.popup-menu .popup-menu__arrow,
.navbar-mini.popup-menu .navbar-right .vk-mask {
display: block;
}
.logout:hover {
color: $menu-text-color-actived;
}
}
/* 右上 */
.right-top {
height: 50px;
}
/* 右下 */
.right-bottom {
padding: 0px 12px;
height: 50px;
background-color: #f5f5f5;
}
::v-deep .navbar .top-bar .item-content {
color: var(--textColor);
}
/* logo模式一开始 纯图片 */
.logo-mode-1 {
display: flex;
align-items: center;
justify-content: center;
.logo-image {
width: 100%;
height: 50px;
display: block;
}
}
/* logo模式一结束 */
/* logo模式二开始 logo+文字 */
.logo-mode-2{
.logo-box{
display: flex;
align-items: center;
justify-content: center;
background-color: #191a23;
height: 50px;
.logo-image{
width: 38px;
height: 38px;
margin-left: 10px;
margin-right: 10px;
border-radius: 50%;
}
.app-name{
width: 100%;
text-align: left;
flex:1;
line-height: 50px;
font-size: 20px;
background-image: -webkit-linear-gradient(left, #147B96, #E6D205 25%, #147B96 50%, #E6D205 75%, #147B96);
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
-webkit-background-size: 200% 100%;
-webkit-animation: masked-animation 4s infinite linear;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
}
@-webkit-keyframes masked-animation {
0% { background-position: 0 0;}
100% { background-position: -100% 0;}
}
}
}
/* logo模式二结束 */
}
</style>