This commit is contained in:
ichynul 2022-06-15 00:31:59 +08:00
commit f4095bec98
23 changed files with 56280 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/assets/lib/

191
LICENSE.txt Normal file
View File

@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "{}" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright 2022 LHY
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

19
README.md Normal file
View File

@ -0,0 +1,19 @@
## elementui cool-admin
### 基于 [Vue + Element] 对 `tpextmyadmin`的UI替换方案
### 部分样式和组件来源于 `cool-admin` : <https://github.com/cool-team-official/cool-admin-vue>
# H+admin后台模板样式
## 关于
替换默认的:`/admin/admin/index`主体页面样式和登录页面`/admin/admin/login`样式
## 使用
1. 下载安装本扩展
2. 打开设置:在[平台设置]-[后台框架]
3. 点击`index主体页面风格`下拉框,选择`COOL-ADMIN样式`
4. 点击`登录页面风格`下拉框,选择`COOL-ADMIN样式` (可选,登录页面可不换)
5. [F5]刷新浏览器生效。

583
admin/view/index/index.html Normal file
View File

@ -0,0 +1,583 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,
maximum-scale=1, user-scalable=no" />
<title>首页 - {$admin_page_title|default=''}</title>
<link rel="icon" href="{$admin_favicon|default=''}" type="image/ico">
<meta name="description" content="{$admin_page_description|default=''}">
<link rel="stylesheet" href="/assets/elementui/css/index.css?v={$admin_assets_ver|default='1.0'}" />
<link rel="stylesheet"
href="/assets/lightyearadmin/css/materialdesignicons.min.css?v={$admin_assets_ver|default='1.0'}">
</head>
<body>
<div id="app" class="hidden" element-loading-background="rgba(0, 0, 0, 0.3)">
<div class="page-layout" :class="{ collapse: menuCollapse }">
<!-- 遮罩层 -->
<div class="page-layout__mask" @click="collapseMenu(true)"></div>
<div class="page-layout__left">
<!-- 侧栏 -->
<div class="app-slider">
<div class="app-slider__logo">
<template v-if="menuCollapse || browser.isMini">
<span @click="collapseMenu(false)"><img class="mini"
src="/assets/elementui/icon/logo/silder-simple.png" /></span>
</template>
<template v-else>
{$admin_logo|raw|default='admin'}
</template>
</div>
<div class="app-slider__menu">
<div class="cl-slider-menu">
<el-menu :default-active="activeTabId" background-color="transparent" :collapse-transition="false"
:collapse="browser.isMini ? false : menuCollapse" @select="leftMenuSelect">
<template v-for="(item, index) in leftMenu">
<el-submenu v-show="!hasTopMenu || item.pid == topActiveId"
v-if="item.children && item.children.length" popper-class="cl-slider-menu__submenu"
:index="item.id">
<template slot="title">
<i class="icon-svg" :class="item.icon"></i>
<span slot="title">{{item.name}}</span>
</template>
<template v-for="(subitem1, index) in item.children">
<el-submenu v-if="subitem1.children && subitem1.children.length"
popper-class="cl-slider-menu__submenu" :index="subitem1.id">
<template slot="title">
<i class="icon-svg" :class="subitem1.icon"></i>
<span slot="title">{{subitem1.name}}</span>
</template>
<template v-for="(subitem2, index) in subitem1.children">
<el-submenu v-if="subitem2.children && subitem2.children.length"
popper-class="cl-slider-menu__submenu" :index="subitem2.id">
<template slot="title">
<i class="icon-svg" :class="subitem2.icon"></i>
<span slot="title" @contextmenu.prevent="stopDefault">{{subitem2.name}}</span>
</template>
</el-submenu>
<el-menu-item v-else :index="subitem2.id">
<i class="icon-svg" :class="subitem2.icon"></i>
<span slot="title" @contextmenu.prevent="stopDefault">{{subitem2.name}}</span>
</el-menu-item>
</template>
</el-submenu>
<el-menu-item v-else :index="subitem1.id">
<i class="icon-svg" :class="subitem1.icon"></i>
<span slot="title" @contextmenu.prevent="stopDefault">{{subitem1.name}}</span>
</el-menu-item>
</template>
</el-submenu>
<el-menu-item v-show="!hasTopMenu || item.pid == topActiveId" v-else :index="item.id" :key="item.id">
<i class="icon-svg" :class="item.icon"></i>
<span slot="title" @contextmenu.prevent="stopDefault">{{item.name}}</span>
</el-menu-item>
</template>
</el-menu>
</div>
</div>
</div>
</div>
<div class="page-layout__right">
<!-- 顶栏 -->
<div class="page-layout__topbar">
<div class="app-topbar">
<div class="app-topbar__collapse" @click="collapseMenu(!menuCollapse)">
<i :class="[menuCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold']"></i>
</div>
<!-- 一级菜单 -->
<div class="app-topbar__menu" v-if="hasTopMenu">
<div class="cl-menu-topbar">
<el-menu :default-active="topActiveId" mode="horizontal" background-color="transparent"
@select="topMenuSelect">
<el-menu-item v-for="(item, index) in topMenu" :index="item.id" :key="item.id">
<i class="icon-svg" :class="item.icon"></i>
<span>{{ item.name }}</span>
</el-menu-item>
</el-menu>
</div>
</div>
<div class="cl-route-nav" v-if="!browser.isMini && !hasTopMenu">
<p class="title">
{$admin_page_title|default='admin'}
</p>
</div>
<div class="flex1"></div>
<!-- 工具栏 -->
<ul class="app-topbar__tools">
<li>
<a title="打开首页" href="/" target="_blank"><i class="el-icon-house"></i></a>
</li>
{if condition="checkUrl(url('/admin/index/clearcache'))"}
<li>
<a title="清空缓存" @click="onCommand('清空缓存|{:url('/admin/index/clearcache')}')"><i
class="el-icon-delete"></i></a>
</li>
{/if}
<!-- 主题 -->
<li @click="openTheme">
<a title="主题"><i class="el-icon-magic-stick"></i></a>
</li>
{:\\tpext\\common\\ExtLoader::trigger('topbar_right_links')}
</ul>
<div class="cl-theme">
<!-- 系统设置 -->
<el-drawer title="系统设置" :visible.sync="drawer.visible" size="300px">
<div class="cl-theme__container">
<div class="cl-theme__color is-card">
<p>主题</p>
<ul>
<el-tooltip v-for="(item, name) in themes" :key="name" :content="item.label" placement="top">
<li :style="{
backgroundColor: item.color
}" @click="setTheme(item)">
<i class="el-icon-check" v-show="item.color == themeInfo.color"></i>
</li>
</el-tooltip>
</ul>
</div>
<div class="cl-theme__switch is-card">
<p>内容区域</p>
<ul>
<li v-if="!browser.isMini">
<el-tooltip class="item" effect="dark" content="顶级菜单放到顶部显示,点击切换左边子菜单" placement="top-start">
<span>显示顶部菜单栏</span>
</el-tooltip>
<el-switch size="mini" v-model="hasTopMenu"></el-switch>
</li>
<li>
<el-tooltip class="item" effect="dark" content="切换顶部菜时激活其所属的第一个子菜单" placement="top-start">
<span>激活第一个子菜单</span>
</el-tooltip>
<el-switch v-popover:popover :disabled="!hasTopMenu" size="mini" v-model="activeFirst">
</el-switch>
</li>
<li>
<el-tooltip class="item" effect="dark" content="收起来或展开左侧菜单" placement="top-start">
<span>收缩左侧菜单栏</span>
</el-tooltip>
<el-switch size="mini" v-model="menuCollapse"></el-switch>
</li>
<li>
<el-tooltip class="item" effect="dark" content="多页面选项卡,可控制在多个页面之间切换" placement="top-start">
<span>显示页面切换栏</span>
</el-tooltip>
<el-switch size="mini" v-model="showProcess"></el-switch>
</li>
</ul>
</div>
</div>
</el-drawer>
</div>
<!-- 用户信息 -->
<div class="app-topbar__user">
<el-dropdown trigger="click" @command="onCommand">
<span class="el-dropdown-link">
<span class="name"
title="{$admin_user.group_name|default=''}">{$admin_user.name|default='Tpext'}</span>
<img class="avatar" src="{$admin_user.avatar|default='/assets/lightyearadmin/images/no-avatar.jpg'}"
alt />
</span>
<el-dropdown-menu slot="dropdown" class="popper-dropdown-menu-user">
<el-dropdown-item command="个人中心|{:url('/admin/index/profile')}">个人中心</el-dropdown-item>
<el-dropdown-item command="修改密码|{:url('/admin/index/changepwd')}">修改密码</el-dropdown-item>
<el-dropdown-item command="exit">退出</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
</div>
<!-- 页面进程 -->
<div v-if="showProcess" class="page-layout__process">
<div class="app-process">
<div class="app-process__left hidden-xs-only" @click="toScroll(true)">
<i class="el-icon-arrow-left"></i>
</div>
<div class="app-process__scroller" ref="scroller">
<div @dblclick="reloadItem(item)" class="app-process__item" v-for="(item, index) in processList"
:key="index" :ref="`item-${item.id}`" :class="{ active: activeTabId == item.id}" :data-index="index"
@click="activeItem(item,index)">
<span>{{ item.label }}</span>
<i class="el-icon-close" v-if="index > 0" @click.stop="onDel(index)"></i>
</div>
</div>
<div class="app-process__right hidden-xs-only" @click="toScroll(false)">
<i class="el-icon-arrow-right"></i>
</div>
<el-dropdown @command="tabDropdownAction">
<span class="el-dropdown-link">
操作<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="current" icon="el-icon-minus">关闭当前</el-dropdown-item>
<el-dropdown-item command="other" icon="el-icon-remove-outline">关闭其他</el-dropdown-item>
<el-dropdown-item command="all" icon="el-icon-circle-close">关闭所有</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
</div>
<!-- 页面视图 -->
<div class="page-layout__container" v-loading="iframeLoading">
<div class="page-layout__view">
<iframe @load="iframeLoading=false" :ref="`iframe-${item.id}`" :class="{ hidden: activeTabId != item.id}"
v-for="(item, index) in processList" :key="index" :name="'iframe'+index" width="100%" height="100%"
:src="item.value" frameborder="0" :data-url="item.value" seamless></iframe>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="/assets/elementui/lib/vue.min.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript" src="/assets/elementui/lib/index.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript" src="/assets/elementui/js/index.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript" src="/assets/elementui/lib/axios.min.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript" src="/assets/lightyearadmin/js/jquery.min.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript" src="/assets/tpextbuilder/js/layer/layer.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript">
var that = null;
var browser = getBrowser();
var themes = getThemes();
var json_str = '{$menus|raw}';
var menuJson = JSON.parse(json_str);
var app = new Vue({
el: "#app",
data() {
return {
hasTopMenu: '{$index_top_menu ?? 0}' == '1' && !browser.isMini,
activeFirst: localStorage.getItem('activeFirst') == 'y',
showProcess: true,
menuCollapse: localStorage.getItem('menuCollapse') == 'y',
topMenu: [],
leftMenu: [],
processList: [
{
id: '{$dashbord.id}',
label: '{$dashbord.name}',
value: '{$dashbord.url}',
}
],
iframeLoading: true,
activeTabId: '{$dashbord.id}',
activeTabIndex: 0,
topActiveId: 0,
drawer: {
visible: false
},
themeInfo: {
label: "",
name: "",
color: ""
},
themes: themes,
}
},
watch: {
hasTopMenu(v) {
this.buildMenu();
},
activeFirst(v) {
localStorage.setItem('activeFirst', v ? 'y' : 'n');
},
menuCollapse(v) {
localStorage.setItem('menuCollapse', v ? 'y' : 'n');
}
},
mounted() {
that = this;
this.buildMenu();
var theme = JSON.parse(localStorage.getItem('index_theme') || '{}');
if (!theme || !theme.name || !theme.color) {
theme = this.themes[0];
}
that.setTheme(theme);
Vue.nextTick(function () {
document.getElementById('app').className = ''
});
},
methods: {
buildMenu() {
var treeObj = treeData(menuJson, 'id', 'pid', 'children');
if (this.hasTopMenu) {
var menuInfo = getSubMenu(treeObj);
this.leftMenu = menuInfo.left;
this.topMenu = menuInfo.top;
}
else {
this.leftMenu = treeObj;
this.topMenu = [];
}
},
collapseMenu(is) {
that.menuCollapse = is;
localStorage.setItem('menuCollapse', is ? 'y' : 'n');
},
onCommand(e) {
if (e == 'exit') {
that.$confirm('确定要注销登录?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
location.replace("{:url('/admin/index/logout')}");
}).catch(() => {
//
});
}
else {
var arr = e.split('|');
var url = arr[1].replace(/\.html/i, '');
var find = this.processList.find(e => (e.value == url || e.value == url + '.html'));
if (find) {
this.activeItem(find);
}
else {
var find0 = menuJson.find(e => (e.url == url || e.url == url + '.html'));
if (find0) {
this.openPage(
{
id: find0.id,
label: arr[0],
value: find0.url,
}
);
}
else {
this.openPage(
{
id: url.replace(/\W/g, ''),
label: arr[0],
value: url,
}
);
}
}
}
},
tabDropdownAction(e) {
if (e == 'current') {
this.onDel(this.processList.findIndex(e => e.id == this.activeTabId));
this.toPath();
}
else if (e == 'other') {
this.processList = this.processList.filter(
e => e.id == this.activeTabId || e.value == "{$dashbord.url}"
);
this.toPath();
}
else if (e == 'all') {
this.processList = this.processList.filter(
e => e.value == "{$dashbord.url}"
);
this.toPath();
}
},
openTheme() {
that.drawer.visible = true;
},
setTheme({ name, color, label }) {
if (that.themeInfo.color == color) {
return false;
}
if (that.themeInfo.label) {
that.$message.success(`切换主题:${label}`);
}
var theme = document.getElementById("theme-style");
var style = theme || document.createElement("link");
style.href = `/assets/elementui/theme/${name}.css`;
if (!theme) {
style.type = "text/css";
style.rel = "stylesheet";
style.id = "theme-style";
document.getElementsByTagName("head").item(0).appendChild(style);
}
// 设置主题色和路径
that.themeInfo.color = color;
that.themeInfo.url = style.href;
that.themeInfo.name = name;
localStorage.setItem('index_theme', JSON.stringify(that.themeInfo));
// 设置 css 变量
document.getElementsByTagName("body")[0].style.setProperty("--color-primary", color);
},
/*tab操作*/
activeItem(item, index) {
if (!item || this.activeTabId == item.id) {
return;
}
this.activeTabId = item.id;
if (index === undefined) {
for (var i in this.processList) {
if (this.processList[i].id == item.id) {
index = i;
break;
}
}
}
var diff = 50 * (index - this.activeTabIndex);//判断是往左点还是往右点,加上惯性
this.activeTabIndex = index;
if (index == 0 || index == this.processList.length - 1) {
var diff = 0;
}
var el = this.$refs[`item-${item.id}`][0];
if (el) {
that.scrollToItem(el.offsetLeft + el.clientWidth - that.$refs["scroller"].clientWidth + diff);
}
},
onDel(index) {
if (index != 0) {
this.processList.splice(index, 1);
var find = this.processList.find(e => e.id == this.activeTabId);
if (!find) {
if (index > 1) {
this.activeItem(this.processList[index - 1], index - 1);
}
else {
this.toPath();
}
}
}
},
toPath() {
var find = this.processList.find(e => e.id == this.activeTabId);
if (!find) {
var next = last(this.processList);
if (next) {
this.activeTabId = next.id;
}
}
},
toScroll(isLeft) {
this.scrollToItem(this.$refs["scroller"].scrollLeft + (isLeft ? -400 : 400));
},
scrollToItem(leftPos) {
this.$refs["scroller"].scrollTo({
left: leftPos,
behavior: "smooth"
});
},
leftMenuSelect(id) {
var find = this.processList.find(e => e.id == id);
if (find) {
this.activeItem(find);
}
else {
var find0 = menuJson.find(e => e.id == id);
if (find0) {
this.openPage(
{
id: find0.id,
label: find0.name,
value: find0.url,
}
);
}
}
},
topMenuSelect(id) {
this.topActiveId = id;
if (!this.activeFirst) {
return;
}
var find = menuJson.find(e => e.pid == id);
if (find) {
var find0 = this.processList.find(e => e.id == find.id);
if (find0) {
this.activeItem(find0);
}
else {
this.openPage(
{
id: find.id,
label: find.name,
value: find.url,
}
);
}
}
},
openPage(item) {
this.processList.push(item);
Vue.nextTick(function () {
setTimeout(function () {
that.activeItem(item, that.processList.length - 1);
}, 100);
});
this.iframeLoading = true;
setTimeout(function () {
this.iframeLoading = false;
}, 3000);
},
reloadItem(item) {
var el = this.$refs[`iframe-${item.id}`][0];
if (el) {
el.contentWindow.location.reload(true);
this.iframeLoading = true;
setTimeout(function () {
this.iframeLoading = false;
}, 3000);
}
},
stopDefault(e) {
e.preventDefault();
e.stopPropagation();
}
},
});
$('a.open-tab').click(function () {
$.fn.multitabs().create(this, true);
return false;
});
((function ($) {
// 兼容 lightyear 的 MultiTabs js
var MultiTabs = function (element) {
var self = this;
self.$element = $(element);
};
MultiTabs.prototype = {
constructor: MultiTabs,
/**
* create tab and return this.
* @param obj the obj to trigger multitabs
* @param active if true, active tab after create
* @returns this Chain structure.
*/
create: function (obj, active) {
var url = $(obj).attr("href"),
text = $.trim($(obj).attr('title') || $(obj).data('title') || $(obj).text());
app.onCommand(text + '|' + url);
return this;
},
};
$.fn.multitabs = function () {
var self = $(this),
did = 'multitabs',
multitabs = $(document).data(did);
if (!multitabs) {
multitabs = new MultiTabs(this);
$(document).data(did, multitabs);
}
return $(document).data(did);
};
})(jQuery));
</script>
</body>
</html>

146
admin/view/index/login.html Normal file
View File

@ -0,0 +1,146 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,
maximum-scale=1, user-scalable=no" />
<title>登录 - {$admin_page_title|default=''}</title>
<link rel="icon" href="{$admin_favicon|default=''}" type="image/ico">
<meta name="description" content="{$admin_page_description|default=''}">
<link rel="stylesheet" href="/assets/elementui/lib/theme-chalk/index.css?v={$admin_assets_ver|default='1.0'}" />
<link rel="stylesheet" href="/assets/elementui/css/login.css?v={$admin_assets_ver|default='1.0'}" />
<script>
if ('{$login_in_top}' == '1' && window != top) {
top.location.replace("{:url('/admin/index/login')}");
document.querySelector('body').innerHTML =
'<div style="background:#fff;z-index:999;padding-top:88px;position:fixed;top:0px;height:10000px;width:100%;text-align:center;font-size:18px;"><p>跳转中...</p></div>';
if (!!(window.attachEvent && !window.opera)) {
document.execCommand("stop");
} else {
window.stop();
}
}
</script>
</head>
<body>
{:\\tpext\\common\\ExtLoader::trigger('admin_login_page')}
<div id="app">
<div class="page-login" {if condition="$admin_login_background_img"
}style="background: url({$admin_login_background_img}) no-repeat;background-size: 100% 100%;" {/if}>
<div class="box">
<img class="logo" src="{$admin_login_logo|default='/assets/lightyearadmin/images/logo-ico.png'}"
alt="{$admin_page_title|default=''}" />
<p class="desc">{$admin_page_title|default=''}</p>
<el-form ref="form" class="form" size="medium">
<el-form-item label="用户名">
<el-input placeholder="请输入您的用户名" v-model="form.username" maxlength="20" auto-complete="off">
</el-input>
</el-form-item>
<el-form-item label="密码">
<el-input type="password" placeholder="请输入密码" v-model="form.password" maxlength="20"
auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="验证码" class="captcha">
<el-input placeholder="请输入图片验证码" maxlength="8" v-model="form.captcha" auto-complete="off"
@keyup.enter.native="next"></el-input>
<div class="login-captcha value" @click="refresh">
<img :src="captchaUrl" alt="captcha" title="点击刷新" alt="captcha" />
</div>
</el-form-item>
</el-form>
<el-button class="submit-btn" @click="submit" :disabled="saving">立即登录</el-button>
{notempty name="$admin_copyright"}
<p class="desc">{$admin_copyright|raw}</p>
{/notempty}
{:\\tpext\\common\\ExtLoader::trigger('admin_login_box_footer')}
</div>
</div>
</div>
<script type="text/javascript" src="/assets/elementui/lib/vue.min.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript" src="/assets/elementui/lib/index.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript" src="/assets/elementui/lib/axios.min.js?v={$admin_assets_ver|default='1.0'}"
charset="utf-8"></script>
<script type="text/javascript">
var that = null;
new Vue({
el: "#app",
data() {
return {
form: {
username: "",
password: "",
captchaId: "",
captcha: ""
},
saving: false,
captchaUrl: "{:url('/admin/index/captcha')}?d=1"
}
},
mounted() {
that = this;
},
methods: {
refresh() {
this.captchaUrl += '1';
this.form.captcha = "";
},
submit() {
if (!this.form.username) {
return this.$message.warning("用户名不能为空");
}
if (!this.form.password) {
return this.$message.warning("密码不能为空");
}
if (!this.form.captcha) {
return this.$message.warning("图片验证码不能为空");
}
this.saving = true;
axios({
method: 'post',
url: location.href,
responseType: 'json',
data: this.form,
headers: {
'x-requested-with': 'xmlhttprequest',
},
}).then(function (res) {
that.saving = false;
var data = res.data;
if (data.code) {
that.$message.success(data.msg || data.message || '登录成功');
setTimeout(function () {
if (window == top || '{$login_in_top}' == '1' || !data.url) {
location.href = "{:url('/admin/index/index')}";
}
else {
location.href = data.url;
}
}, 500);
} else {
that.$message.error(data.msg || data.message || '登录失败', 'warning');
that.captchaUrl += '1';
that.form.captcha = "";
}
}).catch(function (e) {
that.saving = false;
that.$message.error(JSON.stringify(e), 'warning');
});
}
}
});
</script>
{:\\tpext\\common\\ExtLoader::trigger('admin_login_script')}
</body>
</html>

531
assets/css/index.css Normal file
View File

@ -0,0 +1,531 @@
@charset "UTF-8";
/** style from COOL-ADMIN **/
* {
padding: 0;
margin: 0;
outline: none;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
*::-webkit-scrollbar {
width: 10px;
height: 10px;
}
*::-webkit-scrollbar-thumb {
background-color: rgba(144, 147, 153, 0.3);
}
*::-webkit-scrollbar-track {
background: transparent;
}
html,
body {
height: 100%;
width: 100%;
}
#app {
min-height: 100%;
height: 100%;
width: 100%;
}
a {
text-decoration: none;
color: #000;
}
input,
button {
outline: none;
}
input:-webkit-autofill {
box-shadow: 0 0 0px 1000px 2f3447 inset;
}
:export {
colorPrimary: #4165d7;
colorSuccess: #67c23a;
colorDanger: #f56c6c;
colorInfo: #909399;
colorWarning: #e6a23c;
}
.hidden {
display: none;
}
.clearfix:after {
clear: both;
}
.page-layout {
display: flex;
background-color: #f7f7f7;
height: 100%;
width: 100%;
overflow: hidden;
}
.page-layout__left {
overflow: hidden;
height: 100%;
width: 220px;
transition: left 0.2s;
}
.page-layout__right {
display: flex;
flex-direction: column;
height: 100%;
width: calc(100% - 220px);
}
.page-layout__topbar {
margin-bottom: 5px;
}
.page-layout__process {
padding: 0 10px;
margin-bottom: 5px;
}
.page-layout__container {
width: 100%;
box-sizing: border-box;
flex: 1;
overflow: hidden;
}
.page-layout__mask {
position: fixed;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.5);
height: 100%;
width: 100%;
z-index: 999;
}
.page-layout__view {
height: 100%;
width: 100%;
box-sizing: border-box;
padding: 0;
border-radius: 3px;
}
.page-layout__view > iframe {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
@media only screen and (max-width: 768px) {
.page-layout .page-layout__left {
position: absolute;
left: 0;
z-index: 9999;
transition: transform 0.3s cubic-bezier(0.7, 0.3, 0.1, 1), box-shadow 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
}
.page-layout .page-layout__right {
width: 100%;
}
.page-layout.collapse .page-layout__left {
transform: translateX(-100%);
}
.page-layout.collapse .page-layout__mask {
display: none;
}
}
@media only screen and (min-width: 768px) {
.page-layout .page-layout__left,
.page-layout .page-layout__right {
transition: width 0.2s;
}
.page-layout .page-layout__mask {
display: none;
}
.page-layout.collapse .page-layout__left {
width: 64px;
}
.page-layout.collapse .page-layout__right {
width: calc(100% - 64px);
}
}
.app-slider {
height: 100%;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
background-color: #2f3447;
}
.app-slider__logo {
display: flex;
align-items: center;
justify-content: center;
height: 80px;
cursor: pointer;
}
.app-slider__logo img.mini {
height: 30px;
width: 30px;
}
.app-slider__logo img.open {
max-height: 100%;
max-width: 100%;
}
.app-slider__logo span {
color: #fff;
font-weight: bold;
font-size: 16px;
margin-left: 10px;
font-family: inherit;
white-space: nowrap;
}
.app-slider__menu {
height: calc(100% - 80px);
}
.popper-dropdown-menu-user {
width: 120px;
}
.app-topbar {
display: flex;
align-items: center;
height: 50px;
padding: 0 10px;
background-color: #fff;
}
.app-topbar__collapse {
display: flex;
justify-content: center;
align-items: center;
height: 40px;
width: 40px;
cursor: pointer;
margin-right: 10px;
}
.app-topbar__collapse i {
font-size: 22px;
color: #666;
}
.app-topbar .flex1 {
flex: 1;
}
.app-topbar__tools {
display: flex;
margin-right: 20px;
}
.app-topbar__tools li {
list-style: none;
height: 45px;
width: 45px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.app-topbar__tools li i {
font-size: 18px;
}
.app-topbar__tools li i:hover {
opacity: 0.8;
}
.app-topbar__user {
margin-right: 10px;
cursor: pointer;
}
.app-topbar__user .el-dropdown-link {
display: flex;
align-items: center;
}
.app-topbar__user .avatar {
height: 32px;
width: 32px;
border-radius: 32px;
}
.app-topbar__user .name {
white-space: nowrap;
margin-right: 15px;
}
.app-topbar__user .el-icon-arrow-down {
margin-left: 10px;
}
.cl-menu-topbar {
margin-right: 10px;
}
.cl-menu-topbar .el-menu--horizontal.el-menu {
height: 50px;
background: transparent;
overflow: hidden;
}
.cl-menu-topbar .el-menu--horizontal.el-menu .el-menu-item {
display: flex;
align-items: center;
height: 50px;
border-bottom: 0;
padding: 0 7px;
background: transparent;
}
.cl-menu-topbar .el-menu--horizontal.el-menu .el-menu-item span {
font-size: 14px;
margin-left: 1px;
line-height: normal;
}
.cl-menu-topbar .el-menu--horizontal.el-menu .el-menu-item.is-active {
color: var(--color-primary, #4165d7);
border-bottom: none;
}
.cl-menu-topbar .el-menu--horizontal.el-menu .el-menu-item .icon-svg {
margin-right: 5px;
}
.cl-theme .el-drawer__header {
margin-bottom: 20px;
}
.cl-theme .el-drawer__body {
height: calc(100% - 63px);
}
.cl-theme__container {
height: 100%;
overflow: auto;
}
.cl-theme__container::-webkit-scrollbar {
width: 6px;
}
.cl-theme__container::-webkit-scrollbar-thumb {
border-radius: 6px;
background-color: rgba(144, 147, 153, 0.3);
}
.cl-theme .is-card {
padding: 20px 0;
margin: 0 20px 20px 20px;
border-bottom: 1px solid #f7f7f7;
}
.cl-theme .is-card > p {
font-size: 15px;
font-weight: bold;
margin-bottom: 10px;
}
.cl-theme__switch ul {
width: 100%;
}
.cl-theme__switch ul li {
display: flex;
justify-content: space-between;
align-items: center;
height: 40px;
list-style: none;
}
.cl-theme__switch ul li span {
font-size: 13px;
}
.cl-theme__color ul {
display: flex;
flex-wrap: wrap;
margin-top: 10px;
}
.cl-theme__color ul li {
list-style: none;
height: 20px;
width: 20px;
border-radius: 3px;
margin-right: 10px;
margin-top: 10px;
text-align: center;
color: #fff;
line-height: 20px;
}
.cl-theme__color ul li:hover {
opacity: 0.7;
}
.cl-theme__tips {
padding: 10px 20px;
margin-bottom: 50px;
}
.cl-theme__tips .el-button {
margin-top: 20px;
}
.cl-theme__desc {
padding: 10px;
}
.cl-theme__desc-label {
margin-bottom: 10px;
}
.cl-theme__desc li {
list-style: none;
margin-bottom: 20px;
}
i.mdi::before,
i.mdi-set,
[class*=" mdi-"],
[class^=mdi-] {
font-style: normal;
font-weight: 400;
font-size: inherit;
font-variant: normal;
text-transform: none;
line-height: 1;
vertical-align: baseline;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.app-process {
display: flex;
align-items: center;
height: 30px;
position: relative;
}
.app-process__left, .app-process__right {
background-color: #fff;
height: 30px;
line-height: 30px;
padding: 0 2px;
border-radius: 3px;
cursor: pointer;
}
.app-process__left:hover, .app-process__right:hover {
background-color: #eee;
}
.app-process__left {
margin-right: 3px;
}
.app-process__right {
margin-left: 3px;
}
.app-process__scroller {
width: 100%;
flex: 1;
overflow-x: hidden;
overflow-y: hidden;
white-space: nowrap;
}
.app-process__scroller::-webkit-scrollbar {
display: none;
}
.app-process .el-dropdown .el-dropdown-link {
margin-left: 8px;
line-height: 30px;
font-size: 12px;
color: #909399;
cursor: pointer;
}
.app-process__item {
display: inline-flex;
align-items: center;
height: 30px;
line-height: 30px;
padding: 0 10px;
background-color: #fff;
font-size: 12px;
margin-right: 2px;
color: #909399;
cursor: pointer;
position: relative;
}
.app-process__item:last-child {
margin-right: 0;
}
.app-process__item .el-icon-close {
font-size: 12px;
width: auto;
transition: all 0.3s;
visibility: hidden;
position: absolute;
right: 0;
top: 3px;
}
.app-process__item .el-icon-close:hover {
color: #f56c6c;
}
.app-process__item:hover .el-icon-close {
visibility: visible;
}
.app-process__item.active span {
color: var(--color-primary, #4165d7);
}
.app-process__item.active:before {
background-color: var(--color-primary, #4165d7);
}
.app-process__item span::selection {
background-color: transparent;
}
.cl-slider-menu {
height: 100%;
overflow-y: auto;
}
.cl-slider-menu::-webkit-scrollbar {
width: 0;
height: 0;
}
.cl-slider-menu .el-menu {
border-right: 0;
}
.cl-slider-menu .el-menu .el-submenu__title.is-active, .cl-slider-menu .el-menu .el-submenu__title:hover, .cl-slider-menu .el-menu-item.is-active, .cl-slider-menu .el-menu-item:hover {
background-color: var(--color-primary, #4165d7) !important;
color: #fff;
}
.cl-slider-menu .el-menu .el-submenu__title, .cl-slider-menu .el-menu-item, .cl-slider-menu .el-menu__title {
color: #eee;
letter-spacing: 0.5px;
height: 50px;
line-height: 50px;
}
.cl-slider-menu .el-menu .el-submenu__title .icon-svg, .cl-slider-menu .el-menu-item .icon-svg, .cl-slider-menu .el-menu__title .icon-svg {
font-size: 16px;
margin: 0 5px;
}
.cl-slider-menu .el-menu .el-submenu__title span, .cl-slider-menu .el-menu-item span, .cl-slider-menu .el-menu__title span {
font-size: 12px;
letter-spacing: 1px;
display: inline-block;
}
.cl-slider-menu .el-menu--collapse .el-submenu__title .icon-svg {
margin-left: 2px;
font-size: 19px;
}
.cl-slider-menu__submenu {
background-color: #fff;
}
.cl-slider-menu__submenu.el-menu--vertical .el-submenu__title {
display: flex;
align-items: center;
}
.cl-slider-menu__submenu.el-menu--vertical .el-submenu__title .icon-svg {
font-size: 18px;
margin-right: 10px;
}
.cl-slider-menu__submenu.el-menu--vertical .el-menu-item {
display: flex;
align-items: center;
}
.cl-slider-menu__submenu.el-menu--vertical .el-menu-item .icon-svg {
font-size: 18px;
margin-right: 10px;
}
.cl-route-nav {
white-space: nowrap;
}
.cl-route-nav .el-breadcrumb__inner {
font-size: 13px;
padding: 0 10px;
font-weight: normal;
letter-spacing: 1px;
}
.cl-route-nav .title {
font-size: 14px;
font-weight: 500;
margin-left: 5px;
}
.box-card {
min-height: 100%;
}
.box-card > .el-card__header {
padding: 10px 15px;
}
/*# sourceMappingURL=index.css.map */

1
assets/css/index.css.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["index.scss"],"names":[],"mappings":";AAAA;AAEA;EACI;EACA;EACA;EACA;;;AAIJ;EACI;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;;AAGJ;AAAA;EAGI;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI;EACA;;;AAGJ;AAAA;EAEI;;;AAGJ;EACI;;;AAiBJ;EACI,cAfM;EAgBN,cAbY;EAcZ,aAbW;EAcX,WAbS;EAcT,cAbY;;;AAkBhB;EACI;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAIR;EACI;IACI;IACA;IACA;IACA;;EAIJ;IACI;;EAIA;IACI;;EAGJ;IACI;;;AAKZ;EAEI;AAAA;IAEI;;EAGJ;IACI;;EAIA;IACI;;EAGJ;IACI;;;;AAMhB;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;;AAIR;EACI;;;AAIR;EACI;;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAGJ;EACI;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAEA;EACI;;AAMhB;EACI;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAGJ;EACI;EACA;;AAGJ;EACI;;;AAMZ;EACI;;AAEA;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI,OAvRA;EAwRA;;AAGJ;EACI;;;AAQR;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;;AAIR;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAKJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAOZ;EACI;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAMhB;EACI;EACA;;AAEA;EACI;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;EACA;;;AAKZ;AAAA;AAAA;AAAA;EAII;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;AAEA;EAEI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;EACI;;AAGJ;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,OAheD;;AAqeH;EACI;;AAKJ;EACI,OA9eA;;AAifJ;EACI,kBAlfA;;AAsfR;EACI;;;AAKZ;EACI;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;;AAKI;EAEI;EACA;;AAIR;EAGI;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAMA;EACI;EACA;;;AAOpB;EACI;;AAKY;EACI;EACA;;AAEA;EACI;EACA;;AAKZ;EACI;EACA;;AAEA;EACI;EACA;;;AAOpB;EACI;;AAGI;EACI;EACA;EACA;EACA;;AAIR;EACI;EACA;EACA;;;AAIR;EACI;;;AAGJ;EACI","file":"index.css"}

669
assets/css/index.scss Normal file
View File

@ -0,0 +1,669 @@
/** style from COOL-ADMIN **/
* {
padding: 0;
margin: 0;
outline: none;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
"微软雅黑", Arial, sans-serif;
}
*::-webkit-scrollbar {
width: 10px;
height: 10px;
}
*::-webkit-scrollbar-thumb {
background-color: rgba(144, 147, 153, 0.3);
}
*::-webkit-scrollbar-track {
background: transparent;
}
html,
body
{
height: 100%;
width: 100%;
}
#app {
min-height: 100%;
height: 100%;
width: 100%;
}
a {
text-decoration: none;
color: #000;
}
input,
button {
outline: none;
}
input:-webkit-autofill {
box-shadow: 0 0 0px 1000px 2f3447 inset;
}
$primary: #4165d7;
$color-primary: var(--color-primary, $primary);
$color-success: #67c23a;
$color-danger: #f56c6c;
$color-info: #909399;
$color-warning: #e6a23c;
$--color-primary: $primary;
$--color-success: $color-success;
$--color-danger: $color-danger;
$--color-warning: $color-warning;
$--color-info: $color-info;
:export {
colorPrimary: $primary;
colorSuccess: $color-success;
colorDanger: $color-danger;
colorInfo: $color-info;
colorWarning: $color-warning;
}
$--font-path: "../lib/theme-chalk/fonts";
.hidden {
display: none;
}
.clearfix:after {
clear: both
}
.page-layout {
display: flex;
background-color: #f7f7f7;
height: 100%;
width: 100%;
overflow: hidden;
&__left {
overflow: hidden;
height: 100%;
width: 220px;
transition: left 0.2s;
}
&__right {
display: flex;
flex-direction: column;
height: 100%;
width: calc(100% - 220px);
}
&__topbar {
margin-bottom: 5px;
}
&__process {
padding: 0 10px;
margin-bottom: 5px;
}
&__container {
width: 100%;
box-sizing: border-box;
flex: 1;
overflow: hidden;
}
&__mask {
position: fixed;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.5);
height: 100%;
width: 100%;
z-index: 999;
}
&__view {
height: 100%;
width: 100%;
box-sizing: border-box;
padding: 0;
border-radius: 3px;
&>iframe {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
}
}
@media only screen and (max-width: 768px) {
.page-layout__left {
position: absolute;
left: 0;
z-index: 9999;
transition: transform 0.3s cubic-bezier(0.7, 0.3, 0.1, 1),
box-shadow 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
}
.page-layout__right {
width: 100%;
}
&.collapse {
.page-layout__left {
transform: translateX(-100%);
}
.page-layout__mask {
display: none;
}
}
}
@media only screen and (min-width: 768px) {
.page-layout__left,
.page-layout__right {
transition: width 0.2s;
}
.page-layout__mask {
display: none;
}
&.collapse {
.page-layout__left {
width: 64px;
}
.page-layout__right {
width: calc(100% - 64px);
}
}
}
}
.app-slider {
height: 100%;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
background-color: #2f3447;
&__logo {
display: flex;
align-items: center;
justify-content: center;
height: 80px;
cursor: pointer;
img.mini {
height: 30px;
width: 30px;
}
img.open {
max-height: 100%;
max-width: 100%;
}
span {
color: #fff;
font-weight: bold;
font-size: 16px;
margin-left: 10px;
font-family: inherit;
white-space: nowrap;
}
}
&__menu {
height: calc(100% - 80px);
}
}
.popper-dropdown-menu-user {
width: 120px;
}
.app-topbar {
display: flex;
align-items: center;
height: 50px;
padding: 0 10px;
background-color: #fff;
&__collapse {
display: flex;
justify-content: center;
align-items: center;
height: 40px;
width: 40px;
cursor: pointer;
margin-right: 10px;
i {
font-size: 22px;
color: #666;
}
}
.flex1 {
flex: 1;
}
&__tools {
display: flex;
margin-right: 20px;
li {
list-style: none;
height: 45px;
width: 45px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
i {
font-size: 18px;
&:hover {
opacity: 0.8;
}
}
}
}
&__user {
margin-right: 10px;
cursor: pointer;
.el-dropdown-link {
display: flex;
align-items: center;
}
.avatar {
height: 32px;
width: 32px;
border-radius: 32px;
}
.name {
white-space: nowrap;
margin-right: 15px;
}
.el-icon-arrow-down {
margin-left: 10px;
}
}
}
.cl-menu-topbar {
margin-right: 10px;
.el-menu--horizontal.el-menu {
height: 50px;
background: transparent;
overflow: hidden;
.el-menu-item {
display: flex;
align-items: center;
height: 50px;
border-bottom: 0;
padding: 0 7px;
background: transparent;
span {
font-size: 14px;
margin-left: 1px;
line-height: normal;
}
&.is-active {
color: $color-primary;
border-bottom: none;
}
.icon-svg {
margin-right: 5px;
}
}
}
}
.cl-theme {
.el-drawer {
&__header {
margin-bottom: 20px;
}
&__body {
height: calc(100% - 63px);
}
}
&__container {
height: 100%;
overflow: auto;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-thumb {
border-radius: 6px;
background-color: rgba(144, 147, 153, 0.3);
}
}
.is-card {
padding: 20px 0;
margin: 0 20px 20px 20px;
border-bottom: 1px solid #f7f7f7;
&>p {
font-size: 15px;
font-weight: bold;
margin-bottom: 10px;
}
}
&__switch {
ul {
width: 100%;
li {
display: flex;
justify-content: space-between;
align-items: center;
height: 40px;
list-style: none;
span {
font-size: 13px;
}
}
}
}
&__color {
ul {
display: flex;
flex-wrap: wrap;
margin-top: 10px;
li {
list-style: none;
height: 20px;
width: 20px;
border-radius: 3px;
margin-right: 10px;
margin-top: 10px;
text-align: center;
color: #fff;
line-height: 20px;
&:hover {
opacity: 0.7;
}
}
}
}
&__tips {
padding: 10px 20px;
margin-bottom: 50px;
.el-button {
margin-top: 20px;
}
}
&__desc {
padding: 10px;
&-label {
margin-bottom: 10px;
}
li {
list-style: none;
margin-bottom: 20px;
}
}
}
i.mdi::before,
i.mdi-set,
[class*=" mdi-"],
[class^="mdi-"] {
font-style: normal;
font-weight: 400;
font-size: inherit;
font-variant: normal;
text-transform: none;
line-height: 1;
vertical-align: baseline;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.app-process {
display: flex;
align-items: center;
height: 30px;
position: relative;
&__left,
&__right {
background-color: #fff;
height: 30px;
line-height: 30px;
padding: 0 2px;
border-radius: 3px;
cursor: pointer;
&:hover {
background-color: #eee;
}
}
&__left {
margin-right: 3px;
}
&__right {
margin-left: 3px;
}
&__scroller {
width: 100%;
flex: 1;
overflow-x: hidden;
overflow-y: hidden;
white-space: nowrap;
&::-webkit-scrollbar {
display: none;
}
}
.el-dropdown .el-dropdown-link {
margin-left: 8px;
line-height: 30px;
font-size: 12px;
color: #909399;
cursor: pointer;
}
&__item {
display: inline-flex;
align-items: center;
height: 30px;
line-height: 30px;
padding: 0 10px;
background-color: #fff;
font-size: 12px;
margin-right: 2px;
color: #909399;
cursor: pointer;
position: relative;
&:last-child {
margin-right: 0;
}
.el-icon-close {
font-size: 12px;
width: auto;
transition: all 0.3s;
visibility: hidden;
position: absolute;
right: 0;
top: 3px;
&:hover {
color: $color-danger;
}
}
&:hover {
.el-icon-close {
visibility: visible;
}
}
&.active {
span {
color: $color-primary;
}
&:before {
background-color: $color-primary;
}
}
span::selection {
background-color: transparent;
}
}
}
.cl-slider-menu {
height: 100%;
overflow-y: auto;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
.el-menu {
border-right: 0;
.el-submenu__title,
&-item {
&.is-active,
&:hover {
background-color: $color-primary !important;
color: #fff;
}
}
.el-submenu__title,
&-item,
&__title {
color: #eee;
letter-spacing: 0.5px;
height: 50px;
line-height: 50px;
.icon-svg {
font-size: 16px;
margin: 0 5px;
}
span {
font-size: 12px;
letter-spacing: 1px;
display: inline-block;
}
}
&--collapse {
.el-submenu__title {
.icon-svg {
margin-left: 2px;
font-size: 19px;
}
}
}
}
}
.cl-slider-menu__submenu {
background-color: #fff;
&.el-menu {
&--vertical {
.el-submenu {
&__title {
display: flex;
align-items: center;
.icon-svg {
font-size: 18px;
margin-right: 10px;
}
}
}
.el-menu-item {
display: flex;
align-items: center;
.icon-svg {
font-size: 18px;
margin-right: 10px;
}
}
}
}
}
.cl-route-nav {
white-space: nowrap;
.el-breadcrumb {
&__inner {
font-size: 13px;
padding: 0 10px;
font-weight: normal;
letter-spacing: 1px;
}
}
.title {
font-size: 14px;
font-weight: 500;
margin-left: 5px;
}
}
.box-card {
min-height: 100%;
}
.box-card>.el-card__header {
padding: 10px 15px;
}

112
assets/css/login.css Normal file
View File

@ -0,0 +1,112 @@
@charset "UTF-8";
/** style from COOL-ADMIN **/
* {
padding: 0;
margin: 0;
outline: none;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
html,
body,
#app {
height: 100%;
width: 100%;
}
a {
text-decoration: none;
color: #fff;
}
input,
button {
outline: none;
}
input:-webkit-autofill {
box-shadow: 0 0 0px 1000px 2f3447 inset;
}
.page-login {
height: 100vh;
width: 100vw;
position: relative;
background-color: rgb(44, 44, 44);
}
.page-login .box {
background-color: rgba(44, 44, 44, 0.8888);
border-radius: 10px;
padding-bottom: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 500px;
position: absolute;
left: calc(50% - 250px);
top: calc(50% - 280px);
}
.page-login .box .logo {
max-width: 100%;
margin-bottom: 20px;
margin-top: 30px;
}
.page-login .box .desc {
color: #ccc;
font-size: 12px;
margin-bottom: 10px;
margin-top: 10px;
letter-spacing: 1px;
}
.page-login .box .el-form {
width: 300px;
border-radius: 3px;
}
.page-login .box .el-form .el-form-item {
margin-bottom: 20px;
}
.page-login .box .el-form .el-form-item__label {
color: #ccc;
}
.page-login .box .el-form .el-input .el-input__inner {
border: 0;
border-bottom: 0.5px solid #999;
border-radius: 0;
padding: 0 5px;
background-color: transparent;
color: #ccc;
transition: border-color 0.3s;
position: relative;
}
.page-login .box .el-form .el-input .el-input__inner:focus {
border-color: #fff;
color: #fff;
}
.page-login .box .el-form .el-input .el-input__inner:-webkit-autofill {
-webkit-text-fill-color: #fff !important;
-webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
transition: background-color 50000s ease-in-out 0s;
}
.page-login .box .el-form .captcha {
position: relative;
}
.page-login .box .el-form .captcha .value {
position: absolute;
bottom: 2px;
right: 0;
height: 36px;
cursor: pointer;
}
.page-login .box .el-form .captcha .value img {
height: 100%;
}
.page-login .box .submit-btn {
margin-top: 20px;
border-radius: 30px;
margin-bottom: 10px;
padding: 10px 60px;
color: #000;
}
/*# sourceMappingURL=login.css.map */

1
assets/css/login.css.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["login.scss"],"names":[],"mappings":";AAAA;AAEA;EACI;EACA;EACA;EACA;;;AAIJ;AAAA;AAAA;EAGI;EACA;;;AAGJ;EACI;EACA;;;AAGJ;AAAA;EAEI;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;;AAEA;EACI;;AAEA;EACI;;AAKJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;;AAKZ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAMhB;EACI;EACA;EACA;EACA;EACA","file":"login.css"}

126
assets/css/login.scss Normal file
View File

@ -0,0 +1,126 @@
/** style from COOL-ADMIN **/
* {
padding: 0;
margin: 0;
outline: none;
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
"微软雅黑", Arial, sans-serif;
}
html,
body,
#app {
height: 100%;
width: 100%;
}
a {
text-decoration: none;
color: #fff;
}
input,
button {
outline: none;
}
input:-webkit-autofill {
box-shadow: 0 0 0px 1000px 2f3447 inset;
}
.page-login {
height: 100vh;
width: 100vw;
position: relative;
background-color: rgb(44, 44, 44);
.box {
background-color: rgba(44, 44, 44,.8888);
border-radius: 10px;
padding-bottom: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 500px;
position: absolute;
left: calc(50% - 250px);
top: calc(50% - 280px);
.logo {
max-width: 100%;
margin-bottom: 20px;
margin-top: 30px;
}
.desc {
color: #ccc;
font-size: 12px;
margin-bottom: 10px;
margin-top: 10px;
letter-spacing: 1px;
}
.el-form {
width: 300px;
border-radius: 3px;
.el-form-item {
margin-bottom: 20px;
&__label {
color: #ccc;
}
}
.el-input {
.el-input__inner {
border: 0;
border-bottom: 0.5px solid #999;
border-radius: 0;
padding: 0 5px;
background-color: transparent;
color: #ccc;
transition: border-color 0.3s;
position: relative;
&:focus {
border-color: #fff;
color: #fff;
}
&:-webkit-autofill {
-webkit-text-fill-color: #fff !important;
-webkit-box-shadow: 0 0 0px 1000px transparent inset !important;
transition: background-color 50000s ease-in-out 0s;
}
}
}
.captcha {
position: relative;
.value {
position: absolute;
bottom: 2px;
right: 0;
height: 36px;
cursor: pointer;
img {
height: 100%;
}
}
}
}
.submit-btn {
margin-top: 20px;
border-radius: 30px;
margin-bottom: 10px;
padding: 10px 60px;
color: #000;
}
}
}

11
assets/css/readme.md Normal file
View File

@ -0,0 +1,11 @@
scss 转 css :
安装 sass
```bash
npm install sass -g
````
转换:
```bash
sass ./login.scss ./login.css
```

View File

@ -0,0 +1,50 @@
.el-form .el-form-item.tpext-form-item {
margin-bottom: 6px;
padding-right: 14px;
padding-left: 14px;
}
.el-form.search-form .el-form-item.tpext-form-item {
margin-bottom: 4px;
padding-right: 0;
padding-left: 0;
}
.el-form .el-form-item.tpext-form-item .el-form-item__content {
padding-left: 12px;
padding-right: 12px;
}
.el-form-item.tpext-form-item .el-form-item__content.fields-div {
padding-left: 0;
padding-right: 0;
}
.el-form-item__content.fields-div .el-form-item.tpext-form-item {
padding-left: 0;
padding-right: 0;
}
.el-form--label-left.no-margin-bottom .el-form-item__label {
margin-bottom: 0;
}
.el-row {
padding-left: 12px;
padding-right: 12px;
}
a.el-button {
text-decoration: none;
}
.el-form .el-form-item--mini.el-form-item,
.el-form .el-form-item--small.el-form-item {
margin-bottom: 12px
}
.el-form.search-form .el-form-item--mini.el-form-item,
.el-form.search-form .el-form-item--small.el-form-item {
margin-bottom: 3px
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

200
assets/js/index.js Normal file
View File

@ -0,0 +1,200 @@
function getThemes() {
return [
{
label: "钴蓝",
name: "blue",
color: "#4165d7"
},
{
label: "极黑",
name: "black",
color: "#2f3447"
},
{
label: "果绿",
name: "green",
color: "#51C21A"
},
{
label: "酱紫",
name: "purple",
color: "#d0378d"
}
];
}
function getBrowser() {
var clientHeight = document.documentElement.clientHeight, clientWidth = document.documentElement.clientWidth;
// 浏览器信息
var ua = navigator.userAgent.toLowerCase();
// 浏览器类型
var type = (ua.match(/firefox|chrome|safari|opera/g) || "other")[0];
if ((ua.match(/msie|trident/g) || [])[0]) {
type = "msie";
}
// 平台标签
var tag = "";
var isTocuh =
"ontouchstart" in window || ua.indexOf("touch") !== -1 || ua.indexOf("mobile") !== -1;
if (isTocuh) {
if (ua.indexOf("ipad") !== -1) {
tag = "pad";
} else if (ua.indexOf("mobile") !== -1) {
tag = "mobile";
} else if (ua.indexOf("android") !== -1) {
tag = "androidPad";
} else {
tag = "pc";
}
} else {
tag = "pc";
}
// 浏览器内核
var prefix = "";
switch (type) {
case "chrome":
case "safari":
case "mobile":
prefix = "webkit";
break;
case "msie":
prefix = "ms";
break;
case "firefox":
prefix = "Moz";
break;
case "opera":
prefix = "O";
break;
default:
prefix = "webkit";
break;
}
// 操作平台
var plat = ua.indexOf("android") > 0 ? "android" : navigator.platform.toLowerCase();
// 屏幕信息
var screen = "full";
if (clientWidth < 768) {
screen = "xs";
} else if (clientWidth < 992) {
screen = "sm";
} else if (clientWidth < 1200) {
screen = "md";
} else if (clientWidth < 1920) {
screen = "xl";
} else {
screen = "full";
}
// 是否 ios
var isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
// 浏览器版本
var version = (ua.match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1];
// 是否 PC 端
var isPC = tag === "pc";
// 是否移动端
var isMobile = isPC ? false : true;
// 是否移动端 + 屏幕宽过小
var isMini = screen === "xs" || isMobile;
return {
height: clientHeight,
width: clientWidth,
version,
type,
plat,
tag,
prefix,
isMobile,
isIOS,
isPC,
isMini,
screen
};
}
function getSubMenu(treeObj) {
var topMenu = [];
var leftMenu = [];
for (var i in treeObj) {
var children = treeObj[i].children;
if (!children || !children.length) {
if (treeObj[i].url && treeObj[i].url != '#') {
children = [treeObj[i]];
}
}
if (children.length) {
leftMenu = leftMenu.concat(children);
}
if (!treeObj[i].is_home) {
delete treeObj[i].children;
topMenu.push(treeObj[i]);
}
}
return {
left: leftMenu,
top: topMenu,
};
}
/**
* @author CSDN 蔚莱先森
* @param source json数据源
* @param id 主键ID
* @param parendId 父级ID名称
* @param children 子级名称
*/
function treeData(source, id, parentId, children) {
var cloneData = (typeof source == 'object') ? source : JSON.parse(source);
return cloneData.filter(function (father) {
var branchArr = cloneData.filter(function (child) { return father[id] == child[parentId] });
branchArr.length > 0 ? father[children] = branchArr : '';
return father[parentId] == 0
})
}
function isEmpty(value) {
if (isArray(value)) {
return value.length === 0;
}
if (isObject(value)) {
return Object.keys(value).length === 0;
}
return value === "" || value === undefined || value === null;
}
function isArray(value) {
if (typeof Array.isArray === "function") {
return Array.isArray(value);
} else {
return Object.prototype.toString.call(value) === "[object Array]";
}
}
function isObject(value) {
return Object.prototype.toString.call(value) === "[object Object]";
}
function last(data) {
if (isArray(data) || isString(data)) {
return data[data.length - 1];
}
}

856
assets/js/tpextbuilder.js Normal file
View File

@ -0,0 +1,856 @@
(function (w) {
var tpextbuilder = function () { };
tpextbuilder.autoPost = function (classname, url, refresh) {
$('body').on('change', '.' + classname + ' :checkbox', function () {
if ($(this).hasClass('switch-box')) {
var text = $(this).parent('label').prev('input[type="hidden"]');
var name = text.attr('name');
var val = $(this).is(':checked') ? $(this).data('on') : $(this).data('off');
name = name.split('-')[0];
var dataid = $(this).parents('tr.table-row-id').data('id');
tpextbuilder.autoSendData({
id: dataid,
name: name,
value: val
}, url, refresh);
}
else {
var name = $(this).attr('name');
var values = [];
$('.' + classname + " input[name='" + name + "']:checked").each(function (i, e) {
values.push($(e).val());
});
var val = values.join(',');
name = name.split('-')[0];
var dataid = $(this).parents('tr.table-row-id').data('id');
tpextbuilder.autoSendData({
id: dataid,
name: name,
value: val
}, url, refresh);
}
});
$('body').on('change', '.' + classname + ' :radio', function () {
var name = $(this).attr('name');
var val = $('.' + classname + " input[name='" + name + "']:checked").val();
name = name.split('-')[0];
var dataid = $(this).parents('tr.table-row-id').data('id');
tpextbuilder.autoSendData({
id: dataid,
name: name,
value: val
}, url, refresh);
});
var timer = null;
$('body').on('change', '.' + classname + ' input[type="text"]', function () {
clearTimeout(timer);
var that = this;
timer = setTimeout(function () {
var name = $(that).attr('name');
var val = $(that).val();
name = name.split('-')[0];
var dataid = $(that).parents('tr.table-row-id').data('id');
tpextbuilder.autoSendData({
id: dataid,
name: name,
value: val
}, url, refresh);
}, 200);
});
$('body').on('change', '.' + classname + ' textarea', function () {
clearTimeout(timer);
var that = this;
timer = setTimeout(function () {
var name = $(that).attr('name');
var val = $(that).val();
name = name.split('-')[0];
var dataid = $(that).parents('tr.table-row-id').data('id');
tpextbuilder.autoSendData({
id: dataid,
name: name,
value: val
}, url, refresh);
}, 200);
});
$('body').on('change', '.' + classname + ' select', function () {
var name = $(this).attr('name');
var val = $(this).val();
name = name.split('-')[0];
var dataid = $(this).parents('tr.table-row-id').data('id');
tpextbuilder.autoSendData({
id: dataid,
name: name,
value: val
}, url, refresh);
});
};
tpextbuilder.postChecked = function (id, url, confirm) {
var obj = $('#' + id);
if (!obj.size()) {
return;
}
$('body').on('click', '#' + id, function () {
var val = '';
var values = [];
$("input.table-row:checked").each(function (i, e) {
values.push($(e).val());
});
if (values.length == 0) {
lightyear.notify('未选中任何数据', 'warning');
return false;
}
val = values.join(',');
if (confirm && confirm != '0' && confirm != 'false') {
if (confirm == '1') {
var text = $('#' + id).text().trim() || $(this).attr('title');
confirm = '确定要执行批量<strong>' + text + '</strong>操作吗?';
}
$.alert({
title: '操作提示',
content: confirm,
type: 'orange',
buttons: {
confirm: {
text: '确认',
btnClass: 'btn-primary',
action: function () {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
},
cancel: {
text: '取消',
action: function () {
}
}
}
});
} else {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
});
if ($("input.table-row:checked").size() == 0) {
$('#' + id).addClass('disabled');
} else {
$('#' + id).removeClass('disabled');
}
$('body').on('change', 'input.table-row', function () {
if ($("input.table-row:checked").size() == 0) {
$('#' + id).addClass('disabled');
} else {
$('#' + id).removeClass('disabled');
}
});
$('body').on('change', 'input.table-row-checkall', function () {
if ($("input.table-row:checked").is(':checked')) {
$('#' + id).removeClass('disabled');
} else {
$('#' + id).addClass('disabled');
}
});
};
tpextbuilder.openChecked = function (id, url) {
var obj = $('#' + id);
if (!obj.size()) {
return;
}
$('body').on('click', '#' + id, function () {
var val = '';
var values = [];
$("input.table-row:checked").each(function (i, e) {
values.push($(e).val());
});
if (values.length == 0) {
lightyear.notify('未选中任何数据', 'warning');
return false;
}
val = values.join(',');
var size = $(this).data('layer-size');
size = size ? size.split(',') : null;
w.layerOpen(this, size, url + (/.+\?.*/.test(url) ? '&ids=' : '?ids=') + val);
return false;
});
if ($("input.table-row:checked").size() == 0) {
$('#' + id).addClass('disabled');
} else {
$('#' + id).removeClass('disabled');
}
$('body').on('change', 'input.table-row', function () {
if ($("input.table-row:checked").size() == 0) {
$('#' + id).addClass('disabled');
} else {
$('#' + id).removeClass('disabled');
}
});
$('body').on('change', 'input.table-row-checkall', function () {
if ($("input.table-row:checked").is(':checked')) {
$('#' + id).removeClass('disabled');
} else {
$('#' + id).addClass('disabled');
}
});
};
tpextbuilder.postActionsChecked = function (id, confirms) {
var obj = $('#' + id);
if (!obj.size()) {
return;
}
$('body').on('click', '#' + id + '-div .dropdown-menu li a', function () {
var url = $(this).data('url');
var confirm = confirms[url];
var val = '';
var values = [];
$("input.table-row:checked").each(function (i, e) {
values.push($(e).val());
});
if (values.length == 0) {
lightyear.notify('未选中任何数据', 'warning');
return false;
}
val = values.join(',');
if (confirm && confirm != '0' && confirm != 'false') {
if (confirm == '1') {
var text = $(this).text().trim();
confirm = '确定要执行批量<strong>' + text + '</strong>操作吗?';
}
$.alert({
title: '操作提示',
content: confirm,
type: 'orange',
buttons: {
confirm: {
text: '确认',
btnClass: 'btn-primary',
action: function () {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
},
cancel: {
text: '取消',
action: function () {
}
}
}
});
} else {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
});
if ($("input.table-row:checked").size() == 0) {
$('#' + id).addClass('disabled');
} else {
$('#' + id).removeClass('disabled');
}
$('body').on('change', 'input.table-row', function () {
if ($("input.table-row:checked").size() == 0) {
$('#' + id).addClass('disabled');
} else {
$('#' + id).removeClass('disabled');
}
});
$('body').on('change', 'input.table-row-checkall', function () {
if ($("input.table-row:checked").is(':checked')) {
$('#' + id).removeClass('disabled');
} else {
$('#' + id).addClass('disabled');
}
});
};
tpextbuilder.postRowid = function (classname, url, confirm) {
$('body').on('click', '.row-__action__ .' + classname, function () {
var val = $(this).data('id');
if (confirm && confirm != '0' && confirm != 'false') {
if (confirm == '1') {
var text = $(this).text().trim() || $(this).attr('title') || '此';
confirm = '确定要执行<strong>' + text + '</strong>操作吗?';
}
$.alert({
title: '操作提示',
content: confirm,
type: 'orange',
buttons: {
confirm: {
text: '确认',
btnClass: 'btn-primary',
action: function () {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
},
cancel: {
text: '取消',
action: function () {
}
}
}
});
} else {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
});
};
tpextbuilder.postActionsRowid = function (classname, confirms) {
$('body').on('click', '.row-__action__ .' + classname + ' .dropdown-menu li a', function () {
var url = $(this).data('url');
var confirm = confirms[url];
var val = $('.row-__action__ .' + classname).data('id');
if (confirm && confirm != '0' && confirm != 'false') {
if (confirm == '1') {
var text = $(this).text().trim() || $(this).attr('title') || '此';
confirm = '确定要执行<strong>' + text + '</strong>操作吗?';
}
else if (confirm == '2') {
var size = $('.' + classname).find('.btn-actions').data('layer-size');
size = size ? size.split(',') : null;
w.layerOpen(this, size);
return false;
}
$.alert({
title: '操作提示',
content: confirm,
type: 'orange',
buttons: {
confirm: {
text: '确认',
btnClass: 'btn-primary',
action: function () {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
},
cancel: {
text: '取消',
action: function () {
}
}
}
});
} else {
tpextbuilder.autoSendData({
ids: val
}, url, 1);
}
});
};
tpextbuilder.autoSendData = function (data, url, refresh, del) {
data.__token__ = w.__token__;
data._method = /.+?\/(?:destroy|delete|remove|del)(?:\.\w+)?$/.test(url) ? "delete" : "patch";
lightyear.loading('show');
$.ajax({
url: url,
data: data,
type: "POST",
dataType: "json",
success: function (data) {
lightyear.loading('hide');
if (data.__token__) {
w.__token__ = data.__token__;
}
if (data.status || data.code) {
lightyear.notify(data.msg || data.message || '操作成功!', 'success');
if (refresh) {
$('.search-refresh').trigger('click');
}
} else {
lightyear.notify(data.msg || data.message || '操作失败', 'warning');
}
if (data.script || (data.data && data.data.script)) {
var script = data.script || data.data.script;
if ($('#script-div').size()) {
$('#script-div').html(script);
} else {
$('body').append(
'<div class="hidden" id="script-div">' + data.script + '</div>');
}
}
},
error: function () {
lightyear.loading('hide');
lightyear.notify('网络错误', 'danger');
}
});
};
w.tpextbuilder = tpextbuilder;
w.layerOpen = function (obj, size, url) {
var href = url || $(obj).data('url') || $(obj).attr('url') || $(obj).attr('href');
var text = $(obj).data('title') || $(obj).attr('title') || $(obj).text();
if ($(obj).data('layer-size')) {
size = $(obj).data('layer-size').split(',');
}
var winheight = $(window).height() - 14;
layer.open({
type: 2,
title: text,
shadeClose: false,
scrollbar: false,
maxmin: true,
anim: 5, //渐显
shade: 0.3,
maxHeight: winheight,
area: size || ['90%', '400'],
offset: '7px',
content: href,
success: function (layero, index) {
if (!size || size[1] == 'auto' || size[1] == '' || size[1] == '0') {
var iframe = layero.find('iframe').get(0);
var mainheight = $(iframe.contentWindow.document.body).find('.panel-default.content').height() + 10;
if (mainheight < 400) {
mainheight = 400;
}
if (mainheight > winheight - 43) {
mainheight = winheight - 43;
}
$(iframe).height(mainheight);
//layero.css('top', ((winheight - mainheight - 43) / 2) + 'px');
layer.iframeAuto(index);
}
$(':focus').blur();
this.enterEsc = function (event) {
if (event.keyCode === 13) {
return false; //阻止系统默认回车事件
}
if (event.keyCode === 0x1B) {
var index2 = layer.msg('关闭当前弹窗?', {
time: 2000,
btn: ['确定', '取消'],
yes: function (params) {
layer.close(index);
layer.close(index2);
}
});
return false; //阻止系统默认esc事件
}
};
$(document).on('keydown', this.enterEsc); //监听键盘事件,关闭层
},
end: function () {
$(document).off('keydown', this.enterEsc); //解除键盘关闭事件
}
});
return false;
};
})(window);
window.renderFiles = function (elid) {
/*
* 示例上传成功采用返回ID的形式即上传成功以附件表形式存储返回给前端ID值
* 成功返回示例{"status":200,"info":"成功","class":"success","id":1,"picurl":".\/upload\/images\/lyear_5ddfc00174bbb.jpg"}
* 这里设定单图上传为js-upload-image多图上传为js-upload-images
* 存放预览图的div元素命名file_list_*后面的上传按钮的命名filePicker_*这里的*跟隐藏的input的name对应方便单页面中存在有多个上传时区分以及使用
* input上保存上传后的图片ID以及设置上传时的一些参数
*/
elid = elid ? elid : '';
// 通用绑定,
$(elid + '.js-upload-files').each(function () {
var $input_file = $(this).find('input.file-url-input'),
$input_file_name = $(this).data('name');
var jsOptions = window.uploadConfigs[$input_file_name];
var $multiple = jsOptions.multiple, // 是否选择多个文件
$ext = jsOptions.ext.join(','), // 支持的文件后缀
$size = jsOptions.fileSingleSizeLimit; // 支持最大的文件大小
var $file_list = $('#file_list_' + $input_file_name);
var $file_list_upli = $('#file_list_' + $input_file_name + '_upli');
var ratio = window.devicePixelRatio || 1;
var thumbnailWidth = (jsOptions.thumbnailWidth || 165) * ratio;
var thumbnailHeight = (jsOptions.thumbnailHeight || 110) * ratio;
$file_list.find('li.pic-item').each(function (ii, ee) {
var $li = $(ee);
var $btn = $li.find('a.btn-link-pic');
if ($btn && $btn.attr('href')) {
var href = $btn.attr('href');
$img = $li.find('img.preview-img');
if (!jsOptions.isImage && !/.+\.(png|jpg|jpeg|gif|bmp|wbmp|webpg|ico)(\?.*)?$/i.test(href)) {
$btn.removeClass('btn-link-pic');
$btn.attr('target', '_blank');
$img.attr('src', '/index.php/tpextbuilder/index/file/extimg/type/' + href.replace(/.+?\.(\w+)$/, '$1'));
}
else {
$img.attr('src', href);
}
$img.css({
'display': 'block',
'max-width': thumbnailWidth + 'px',
'margin': '0 auto'
}).parent('div').css({
'height': thumbnailHeight + 'px',
'width': thumbnailWidth + 'px',
});
}
});
if (jsOptions.canUpload || !jsOptions.istable) {
$file_list_upli.css({
'height': thumbnailHeight + 'px',
'width': thumbnailWidth + 'px',
'padding-left': '10px',
'display': 'block',
});
var uploader = WebUploader.create({
auto: true,
chunked: true,
prepareNextFile: true,
duplicate: jsOptions.duplicate ? true : false,
resize: jsOptions.resize ? true : false,
swf: jsOptions.swf_url,
server: jsOptions.upload_url,
pick: {
id: '#picker_' + $input_file_name,
multiple: $multiple
},
fileSingleSizeLimit: $size,
fileNumLimit: 99,
fileSizeLimit: jsOptions.fileSizeLimit,
accept: {
title: '文件',
extensions: $ext,
mimeTypes: jsOptions.mimeTypes || '*/*'
},
thumb: {
// 图片质量只有type为`image/jpeg`的时候才有效。
quality: 70,
// 是否允许放大如果想要生成小图的时候不失真此选项应该设置为false.
allowMagnify: false,
// 是否允许裁剪。
crop: true,
// 为空的话则保留原有图片格式。
// 否则强制转换成指定的类型。
type: 'image/jpeg'
}
});
uploader.on('beforeFileQueued', function (file) {
if (jsOptions.fileNumLimit > 1 && $file_list.find('li.pic-item').size() >= jsOptions.fileNumLimit) {
lightyear.notify('最多允许上传' + jsOptions.fileNumLimit + '个文件', 'danger');
return false;
}
});
uploader.on('fileQueued', function (file) {
var $li = $('<li class="pic-item" id="' + file.id + '">' +
' <figure>' +
'<div>' +
' <img>' +
'</div>' +
' <figcaption>' +
' <a class="btn btn-xs btn-round btn-square btn-primary btn-link-pic" href="javascript:;"><i class="mdi mdi-eye"></i></a>' +
' <a class="btn btn-xs btn-round btn-square btn-danger btn-remove-pic" href="javascript:;"><i class="mdi mdi-delete"></i></a>' +
' </figcaption>' +
' </figure>' +
'</li>'),
$img = $li.find('img');
if (jsOptions.fileNumLimit <= 1) {
$file_list.find('li.pic-item').remove();
}
$file_list.append($li);
uploader.makeThumb(file, function (error, src) {
if (!jsOptions.isImage && !/(png|jpg|jpeg|gif|bmp|wbmp|webpg|ico)$/i.test(file.ext) && error) {
src = '/index.php/tpextbuilder/index/file/extimg/type/' + file.ext;
$img.addClass('cantpreview');
}
else {
$img.addClass('imgpreview');
}
$img.attr('src', src);
$img.css({
'display': 'block',
'max-width': thumbnailWidth + 'px',
'margin': '0 auto'
}).parent('div').css({
'height': thumbnailHeight + 'px',
'width': thumbnailWidth + 'px',
});
}, thumbnailWidth, thumbnailHeight);
$('<div class="progress progress-xs"><div class="progress-bar progress-bar-primary progress-bar-striped" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div></div>').appendTo($li);
});
uploader.on('uploadProgress', function (file, percentage) {
var $percent = $('#' + file.id).find('.progress-bar');
$percent.css('width', percentage * 100 + '%');
});
uploader.on('uploadSuccess', function (file, response) {
var $li = $('#' + file.id);
if (response.status == 200) { // 返回200成功
if (jsOptions.fileNumLimit > 1) {
if ($input_file.val()) {
$input_file.val($input_file.val() + ',' + response.picurl).trigger('change');
} else {
$input_file.val(response.picurl).trigger('change');
}
$li.find('.btn-remove-pic').attr('data-id', response.id).attr('data-url', response.picurl);
} else {
$input_file.val(response.picurl).trigger('change');
}
}
$('<div class="' + response.class + ' upload-result"></div>').text(response.info + '(' + $file_list.find('li.pic-item').size() + '/' + jsOptions.fileNumLimit + ')').appendTo($li.find('figure'));
if ($li.find('.cantpreview').size() > 0) {
$li.find('a.btn-link-pic').attr('href', response.picurl).removeClass('btn-link-pic').attr('target', '_blank');
} else {
$li.find('.imgpreview').attr('src', response.picurl);
$li.find('a.btn-link-pic').attr('href', response.picurl);
}
setTimeout(function () {
$li.find('.upload-result').remove();
}, 3000);
});
uploader.on('uploadError', function (file) {
var $li = $('#' + file.id);
$('<div class="error upload-result">上传失败</div>').appendTo($li).find('figure');
setTimeout(function () {
$li.remove();
}, 3000);
});
uploader.on('error', function (type) {
switch (type) {
case 'Q_TYPE_DENIED':
lightyear.notify('文件类型不正确,只允许上传后缀名为:' + $ext + ',请重新上传!', 'danger');
break;
case 'F_EXCEED_SIZE':
lightyear.notify('文件不得超过' + ($size / 1024) + 'kb请重新上传', 'danger');
break;
}
});
uploader.on('uploadComplete', function (file) {
setTimeout(function () {
$('#' + file.id).find('.progress').remove();
}, 500);
});
// 删除操作
$file_list.delegate('.btn-remove-pic', 'click', function () {
var url = $(this).data('url');
var that = $(this);
$.alert({
title: '提示',
content: '确认要删除此文件吗?',
buttons: {
confirm: {
text: '确认',
btnClass: 'btn-primary',
action: function () {
if (jsOptions.fileNumLimit > 1) {
var ids = $input_file.val().split(',');
if (url) {
for (var i = 0; i < ids.length; i++) {
if (ids[i] == url) {
ids.splice(i, 1);
break;
}
}
$input_file.val(ids.join(',')).trigger('change');
}
} else {
$input_file.val('').trigger('change');
}
that.closest('.pic-item').remove();
}
},
cancel: {
text: '取消',
action: function () {
}
}
}
});
});
}
// 接入图片查看插件
$(this).magnificPopup({
delegate: 'a.btn-link-pic',
type: 'image',
gallery: {
enabled: true
}
});
});
};
window.chooseFile = function (id, $input_file_name) {
var jsOptions = window.uploadConfigs[$input_file_name];
var $file_list = $('#file_list_' + $input_file_name);
var chooseUrl = jsOptions.chooseUrl || '/admin/attachment/index?';
if (jsOptions.fileNumLimit > 1 && $file_list.find('li.pic-item').size() >= jsOptions.fileNumLimit) {
lightyear.notify('最多允许上传' + jsOptions.fileNumLimit + '个文件', 'danger');
return false;
}
var obj = $('#' + id);
var size = ['98%', '98%'];
if (obj.data('layer-size')) {
size = obj.data('layer-size').split(',');
}
layer.open({
type: 2,
title: '文件选择',
shadeClose: false,
scrollbar: false,
shade: 0.3,
anim: 2, //从最底部往上滑入
area: size,
content: chooseUrl + 'choose=1&id=' + id + '&limit=' + jsOptions.fileNumLimit + '&ext=' + jsOptions.ext.join(','),
success: function (layero, index) {
$(':focus').blur();
this.enterEsc = function (event) {
if (event.keyCode === 13) {
return false; //阻止系统默认回车事件
}
if (event.keyCode === 0x1B) {
var index2 = layer.msg('关闭当前弹窗?', {
time: 2000,
btn: ['确定', '取消'],
yes: function (params) {
layer.close(index);
layer.close(index2);
}
});
return false; //阻止系统默认esc事件
}
};
$(document).on('keydown', this.enterEsc); //监听键盘事件,关闭层
},
end: function () {
$(document).off('keydown', this.enterEsc); //解除键盘关闭事件
window.refreshFiles(jsOptions, $file_list, obj);
}
});
};
window.refreshFiles = function (jsOptions, $file_list, $input_file) {
var ratio = window.devicePixelRatio || 1;
var thumbnailWidth = (jsOptions.thumbnailWidth || 165) * ratio;
var thumbnailHeight = (jsOptions.thumbnailHeight || 110) * ratio;
$file_list.find('li.pic-item').remove();
if ($input_file.val().trim() == '') {
return;
}
var filesArr = $input_file.val().split(',');
for (var i in filesArr) {
var src = filesArr[i];
var $li = $('<li class="pic-item" id="fild' + i + '">' +
' <figure>' +
'<div style="width:' + thumbnailWidth + 'px;height:' + thumbnailHeight + 'px">' +
' <img class="preview-img" />' +
'</div>' +
' <figcaption>' +
' <a class="btn btn-xs btn-round btn-square btn-primary btn-link-pic" href="' + src + '"><i class="mdi mdi-eye"></i></a>' +
' <a class="btn btn-xs btn-round btn-square btn-danger btn-remove-pic" href="javascript:;"><i class="mdi mdi-delete"></i></a>' +
' </figcaption>' +
' </figure>' +
'</li>');
var $img = $li.find('img');
var $btn = $li.find('a.btn-link-pic');
$li.find('.btn-remove-pic').attr('data-id', i).attr('data-url', src);
$file_list.append($li);
if (!jsOptions.isImage && !/.+\.(png|jpg|jpeg|gif|bmp|wbmp|webpg|ico)$/i.test(src)) {
src = '/index.php/tpextbuilder/index/file/extimg/type/' + src.replace(/.+?\.(\w+)$/, '$1');
$img.addClass('cantpreview');
$btn.removeClass('btn-link-pic');
$btn.attr('target', '_blank');
}
$img.attr('src', src);
$img.css({
'display': 'block',
'max-width': thumbnailWidth + 'px',
'margin': '0 auto'
}).parent('div').css({
'height': thumbnailHeight + 'px',
'width': thumbnailWidth + 'px',
});
}
}
$(function () {
//动态选择框,上下级选中状态变化
window.renderFiles();
});

13169
assets/theme/black.css Normal file

File diff suppressed because it is too large Load Diff

13215
assets/theme/blue.css Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

13215
assets/theme/green.css Normal file

File diff suppressed because it is too large Load Diff

13154
assets/theme/purple.css Normal file

File diff suppressed because it is too large Load Diff

30
common/Resource.php Normal file
View File

@ -0,0 +1,30 @@
<?php
namespace cooladmin\common;
use tpext\common\Resource as baseResource;
use tpext\myadmin\common\Module as adminModule;
class Resource extends baseResource
{
protected $version = '1.0.1';
protected $name = 'cool.admin';
protected $title = 'Cool-Admin';
protected $description = '基于[Vue+Element]COOL-ADMIN样式UI';
protected $root = __DIR__ . '/../';
protected $assets = 'assets';
public function loaded()
{
$indexView = $this->getRoot() . implode(DIRECTORY_SEPARATOR, ['admin', 'view', 'index', 'index.html']);
$loginView = $this->getRoot() . implode(DIRECTORY_SEPARATOR, ['admin', 'view', 'index', 'login.html']);
adminModule::getInstance()->addIndexView($indexView, 'COOL-ADMIN样式');
adminModule::getInstance()->addLoginView($loginView, 'COOL-ADMIN样式');
}
}