Commit 3653ecb9 authored by wanghuan's avatar wanghuan

上传aserver-ui的nojc分支

parents
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
FROM nginx:stable
LABEL maintainer="dengguoqi@archser.com"
COPY dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
\ No newline at end of file
# aserver-ui
## 准备
设置私服地址
```
npm config set registry=http://archser.com:8081/repository/npm-group/
```
## 安装项目依赖模块
```
npm install
```
## 开发模式,热加载
```
npm run serve
```
## 产品模式,最小化编译
```
npm run build
```
## 语法检查
```
npm run lint
```
\ No newline at end of file
module.exports = {
presets: [
[
"@vue/app",
{
"useBuiltIns": "entry"
}
]
],
}
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml application/javascript text/css application/octet-stream;
gzip_vary on;
# websocke 连接需要下面的配置
map $http_upgrade $connection_upgrade {
websocket upgrade;
default $sent_http_connection;
}
server {
listen 80;
#server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
location ~ \.(gif|jpg|jpeg|bmp|png|ico|txt|mp3|mp4|swf|css|js|ttf)$ {
root /usr/share/nginx/html;
expires max;
}
location /aserver {
proxy_pass http://aserver:11038/aserver;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# websocke 连接需要下面的配置
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "aserver-ui",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --port 11028",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@archser/layout-ui": "^0.8.2",
"babel-polyfill": "^6.26.0",
"core-js": "^2.6.10",
"crypto-js": "^4.0.0",
"es6-promise": "^4.2.8",
"iview": "^3.5.4",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"qs": "^6.9.1",
"sm-crypto": "^0.1.0",
"vue": "^2.6.10",
"vue-router": "^3.1.3",
"vuex": "^3.1.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.12.1",
"@vue/cli-plugin-eslint": "^3.12.1",
"@vue/cli-service": "^4.1.2",
"babel-eslint": "^10.0.3",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.2.3",
"vue-template-compiler": "^2.6.10"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {
"no-unused-vars": "off"
},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"repository": {
"type": "git",
"url": "http://gitlab.archser.com/spb/aserver-ui.git"
},
"license": "MIT",
"browserslist": [
"> 1%",
"last 2 versions"
],
"prettier": {
"semi": false,
"printwidth": 180,
"singleQuote": true
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>aserver-ui</title>
</head>
<body>
<noscript>
<strong>We're sorry but aserver-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>登录</title>
</head>
<body>
<noscript>
<strong>We're sorry but aserver-ui doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
import { axios } from '@archser/layout-ui'
import myaxios from 'axios'
const SERVICE_URL = '/aserver'
//获取操作文件列表
export const getList = (params) => {
return axios.request({
url: SERVICE_URL + '/helper/getList',
params:params,//LiuKexin 20201123 修改传递参数的格式
method: 'post'
})
}
export const edit = (param) => {
return axios.request({
url: SERVICE_URL + '/helper/edit',
data: param,
method: 'post'
})
}
export const remove = (ids) => {
return axios.request({
url: SERVICE_URL + '/helper/remove',
data: {
ids
},
method: 'post'
})
}
export const add = param => {
return myaxios({
url: SERVICE_URL + '/helper/add',
data: param,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
\ No newline at end of file
import { axios } from '@archser/layout-ui'
const SERVICE_URL = '/aserver'
/**
* LiuKexin 20210311 根据用户名获取设置首页
* @param {*} params
* @returns
*/
export const getUserHome = params => {
return axios.request({
url: SERVICE_URL + '/getUserHome',
data: params,
method: 'post'
})
}
//修改密码
export const update = (username, newPwd) => {
return axios.request({
url: SERVICE_URL + '/updatePassword',
data: {
username,
newPwd
},
method: 'post'
})
}
/**
* @description: 验证密码强度
* @Author: ChengYaqing
* @Date: 2020-10-30 10:30:45
*/
export const verifyPassword = params => {
return axios.request({
url: SERVICE_URL + '/verifyPassword',
data: params,
method: 'post'
})
}
/**
* 检查SN
*/
export const snVerify = () => {
return axios.request({
url: SERVICE_URL + '/sn/snVerify',
method: 'post'
})
}
/**
* 注册SN
* @param {*} params
*/
export const registered = params => {
return axios.request({
url: SERVICE_URL + '/sn/registered',
data: params,
method: 'post'
})
}
export const ruleValidate = {
organName: [
{ required: true, message: '机构名不能为空', trigger: 'blur' }
],
uniqueCode: [
{ required: true, message: '注册码不能为空', trigger: 'blur' },
]
}
\ No newline at end of file
import { axios } from '@archser/layout-ui'
const SERVICE_URL = '/aserver/menu'
/**
* 根据SysId获取菜单列表
*/
export const getMenuList = params => {
return axios.request({
url: SERVICE_URL + '/getMenuList',
params: params,
method: 'get'
})
}
/**
* 保存菜单数据
*/
export const saveMenuData = params => {
return axios.request({
url: SERVICE_URL + '/saveMenuData',
params: params,
method: 'post'
})
}
/**
* 删除菜单数据
*/
export const deleteMenu = params => {
return axios.request({
url: SERVICE_URL + '/deleteMenu',
params: params,
method: 'post'
})
}
import { axios } from '@archser/layout-ui'
import myaxios from 'axios'
const SERVICE_URL = '/aserver'
/**
* 获取所有系统
*/
export const getSettings = () => {
return axios.get('/aserver/setting/all')
}
export const add = config => {
return axios.request({
url: SERVICE_URL + '/setting/add',
data: config,
method: 'post'
})
}
export const dele = data => {
return axios.request({
url: SERVICE_URL + '/setting/dele',
data,
method: 'post'
})
}
export const findConfigList = (params) => {
return axios.request({
url: SERVICE_URL + '/setting/findConfigList',
params: params,
method: 'post'
})
}
/**
* Liukexin 20200930 更改系统名称和图标
* @param {*} param
*/
export const changeSetting = param => {
return myaxios({
url: SERVICE_URL + '/setting/changeSetting',
method: 'post',
data: param,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
import { axios } from '@archser/layout-ui'
const SERVICE_URL = '/aserver'
/**
* 获取所有系统
*/
export const getSystems = (params) => {
return axios.request({
url: SERVICE_URL + '/system',
params: params,
method: 'get'
})
}
export const create = () => {
return axios.get(SERVICE_URL + '/key/create')
}
export const addorEdit = params => {
return axios.request({
url: SERVICE_URL + '/system/addorEdit',
data: params,
method: 'post'
})
}
export const dele = params => {
return axios.request({
url: SERVICE_URL + '/system/dele',
data: params,
method: 'post'
})
}
<template>
<div class="searchClass" :style="width?('width: '+(width-37)+'px;'):'width:100%;'">
<iInput
class="searchInputClass"
:placeholder="placeholder"
@on-clear="clear"
@on-enter="search"
@on-change="change"
@on-focus="focus"
@on-blur="blur"
@on-keyup="keyup"
@on-keypress="keypress"
@on-keydown="keydown"
:disabled="disabled"
v-model="inputValue"
clearable/>
<Button type="primary" @click="search" class="searchButtonClass">
<Icon :custom="'fa '+custom+' fa-fw'" aria-hidden="true"/>
</Button>
</div>
</template>
<script>
export default {
name: 'SearchInput',
props: {
custom: {
type: String,
default: 'fa-search'
},
disabled: {
type: Boolean,
default: false
},
placeholder: {
type: String,
default: '请输入搜索内容'
},
width: {
type: Number,
default: null
},
value: {
type: String,
default: ''
},
original: {// 是否不处理输入的内容,即:不将单引号转换为两个单引号
type: Boolean,
defalut: false,
}
},
computed: {
},
data() {
return {
inputValue: this.getValue(this.value)
}
},
methods: {
/**
* @description: // CP-1820 替换一个单引号为两个单引号 huwenbin 2020/12/21
* @author: huwenbin
* @Date: 2020/12/21 11:35
*/
getValue(value) {
if (value != null && !this.original) {
return value.replace(/''/g, "'")
}
return value
},
/**
* @description: // CP-1820 替换一个单引号为两个单引号 huwenbin 2020/12/21
* @author: huwenbin
* @Date: 2020/12/21 11:35
*/
convertValue(value) {
if (value != null && !this.original) {
return value.replace(/'/g, "''")
}
return value
},
focus() {
this.$emit('on-focus')
},
blur() {
this.$emit('on-blur')
},
enter() {
this.$emit('on-enter')
},
keyup() {
this.$emit('on-keyup')
},
keypress() {
this.$emit('on-keypress')
},
keydown() {
this.$emit('on-keydown')
},
change() {
this.$emit('update:value', this.convertValue(this.inputValue))
this.$emit('on-change')
},
clear() {
this.$emit('on-clear')
},
search() {
this.$emit('on-click')
}
}
}
</script>
<style>
.searchClass {
display: inline-flex;
border-radius: 5px;
border: 1px solid rgba(200, 200, 200, 0);
}
.searchClass:hover{
border-color: #57a3f3;
-webkit-transition: all .5s;
transition: all .5s;
}
.searchClass:focus-within{
border-color: #57a3f3;
-webkit-box-shadow: 0 0 0 2px rgba(45,140,240,.2);
box-shadow: 0 0 0 2px rgba(45,140,240,.2);
background-position: 0 0%;
-webkit-transition: all .5s;
transition: all .5s;
}
.searchClass .searchButtonClass {
width: 35px;
text-align: center;
padding-left: 7px;
background: #fff;
color: #808695;
border-bottom-left-radius: 0px;
border-top-left-radius: 0px;
border: 1px solid #dcdee2;
border-left: 0px;
}
.searchClass .searchButtonClass:focus {
outline: none;
box-shadow: none;
}
.searchClass .searchInputClass .ivu-input-icon {
right: 0px;
}
.searchClass .searchInputClass input{
border-bottom-right-radius: 0px;
border-top-right-radius: 0px;
border-right: 0px;
}
.searchClass .searchInputClass input:focus{
outline: none;
border: 1px solid #dcdee2;
border-right: 0px;
box-shadow: none;
}
.searchClass .searchInputClass input:hover{
border: 1px solid #dcdee2;
border-right: 0px;
}
</style>
import Vue from 'vue'
import axios from 'axios'
import qs from 'qs'
import Login from './views/login/Login.vue'
let ajax = axios.create({
timeout: 30000,
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
transformRequest: [
function(data) {
return qs.stringify(data)
}
],
paramsSerializer: function(data) {
return qs.stringify(data)
}
})
Vue.config.productionTip = false
Vue.prototype.$http = ajax
new Vue({
render: h => h(Login)
}).$mount('#app')
import { layout } from '@archser/layout-ui'
import 'babel-polyfill'
import Es6Promise from 'es6-promise'
Es6Promise.polyfill()
import '@archser/layout-ui/dist/layout-ui.css'
import router from './router'
layout(router)
\ No newline at end of file
/**
* 路由
*/
export default {
routes: [
{
path: '/',
name: 'login',
meta: {
title: '应用管理'
},
component: () => import('@/views/login/login.vue')
}
]
}
\ No newline at end of file
/**
* 路由
*/
export default {
routes: [
{
path: '/',
name: 'home',
redirect: '/home',
children: [
{
path: 'home',
name: 'home_index',
meta: {
title: '应用管理'
},
component: () => import('@/views/apply/apply.vue')
},
{
path: 'setting',
name: 'setting',
meta: {
title: '配置'
},
component: () => import('@/views/setting/Setting.vue')
},
{
path: 'help',
name: 'help',
meta: {
title: '帮助下载'
},
component: () => import('@/views/helpCenter/help-download.vue')
},
{
path: 'helpManager',
name: 'helpManager',
meta: {
title: '帮助中心管理'
},
component: () => import('@/views/helpCenter/help-Manager.vue')
},
]
}
]
}
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
}
})
<template>
<div class="apply-app-outer">
<div class="apply-app-container">
<div class="apply-toolbar">
<Row span="24">
<!-- LiuKexin 20201225 调整样式 -->
<Button type="primary" style="padding: 0 8px" @click.stop="addSystem">
<Icon custom="fa fa-plus-circle fa-fw" aria-hidden="true"></Icon
>添加&nbsp;&nbsp;
</Button>
<Button
type="text"
style="margin-left: 8px; padding: 0px"
@click.stop="deleSystem"
>
<Icon
custom="fa fa-trash fa-fw"
aria-hidden="true"
style="color: red"
></Icon
>删除
</Button>
<Divider type="vertical" />
<!-- <ButtonGroup> -->
<!-- <Button @click.stop="addSystem">
<Icon custom="fa fa-fw fa-plus"></Icon>添加
</Button>
<Button @click="deleSystem">
<Icon custom="fa fa-fw fa-close" style="color:red;"></Icon>删除
</Button> -->
<!-- </ButtonGroup>&nbsp;&nbsp;&nbsp; -->
<!-- <ButtonGroup>
<Button style="border-radius:5px">
<Icon custom="fa fa-fw fa-check-circle"></Icon>测试
</Button>
<Button style="display:none"></Button>
</ButtonGroup>-->
<SearchInput
:value.sync="searchText"
@on-clear="clearSearch"
@on-click="searchByKeyword"
:width="260"
/>
</Row>
</div>
<div>
<Table
border
:columns="columns"
:data="systems"
:loading="loading"
:height="tableheight"
@on-selection-change="onSelect"
stripe
>
<!-- durui 20201117 DAG-393 统一按钮和表单字体 去掉 size="small" -->
<template slot-scope="{ row, index }" slot="edit">
<ButtonGroup>
<Button
class="operate-button"
@click.stop="editSystem(row, index)"
>
<Icon custom="fa fa-fw fa-edit"></Icon>
</Button>
<Button class="operate-button" @click.stop="showMenuData(row)">
<i class="fa fa-bars" aria-hidden="true"></i>
</Button>
</ButtonGroup>
</template>
<!-- LiuKexin 20210118 私钥和公钥的文字提示 start -->
<template slot-scope="{ row }" v-for="field in fieldSlotList" :slot="field.name">
<div :key="field.index">
<Tooltip
:transfer="true"
placement="bottom-start"
style="margin-top: 8px; width: 100%"
v-if="row[field.name] != null && row[field.name] != ''"
>
<p class="table-content">{{ row[field.name] }}</p>
<p slot="content" class="file-code-content" style="word-break:break-all;whiteSpace:normal">
{{ row[field.name] }}
</p>
</Tooltip>
<p class="table-content" v-else>{{ row[field.name] }}</p>
</div>
</template>
<!-- LiuKexin 20210118 私钥和公钥的文字提示 end -->
</Table>
</div>
<template>
<Modal
v-model="modal"
width="660"
:footer-hide="true"
class="modalClass"
>
<p slot="header">
<span>
<Icon :custom="'fa fa-' + sideComponentIcon"></Icon>
{{ title }}</span
>
</p>
<div class="form-editor">
<iForm
:model="system"
:label-width="80"
ref="formValidate"
:rules="ruleValidate"
>
<Row>
<iCol span="12">
<FormItem label="名称" prop="name">
<iInput
v-model.trim="system.name"
placeholder="请输入英文系统名称"
></iInput>
</FormItem>
</iCol>
<iCol span="12">
<FormItem label="类型" prop="type">
<Select v-model="system.type">
<Option
v-for="item in typeList"
:key="item.value"
:value="item.value"
>{{ item.text }}</Option
>
</Select>
</FormItem>
</iCol>
<iCol span="24">
<FormItem label="中文名" prop="title">
<iInput
v-model.trim="system.title"
placeholder="请输入系统中文显示名称"
></iInput>
</FormItem>
</iCol>
<iCol span="12">
<FormItem label="URL" prop="url">
<iInput
v-model.trim="system.url"
placeholder="请输入系统访问地址"
></iInput>
</FormItem>
</iCol>
<iCol span="12">
<FormItem label="服务" prop="service">
<iInput
v-model="system.service"
placeholder="输入系统服务访问地址"
></iInput>
</FormItem>
</iCol>
<iCol span="12">
<FormItem label="密钥ID" prop="keyid">
<iInput v-model="system.keyid" readonly></iInput>
</FormItem>
</iCol>
<iCol span="12">
<Button
icon="md-color-wand"
type="primary"
@click="createKey"
style="margin-left: 10px; margin-top: 0px"
>新建</Button
>
</iCol>
<iCol span="24">
<FormItem label="私钥" prop="privatekey">
<iInput
v-model="system.privatekey"
type="textarea"
readonly
></iInput>
</FormItem>
</iCol>
<iCol span="24">
<FormItem label="公钥" prop="publickey">
<iInput
v-model="system.publickey"
type="textarea"
readonly
></iInput>
</FormItem>
</iCol>
<iCol span="24">
<FormItem label="描述" prop="description">
<iInput
placeholder="请输入描述信息"
v-model.trim="system.description"
type="textarea"
></iInput>
</FormItem>
</iCol>
<!-- Liukexin 20201228 按钮靠右 -->
<iCol span="24" style="height: 32px">
<FormItem class="button-toolbar" style="text-align: right">
<Button @click="reset()" style="margin-left: 8px">
<!-- LiuKexin 20201216 添加图标 -->
<Icon custom="fa fa-refresh fa-fw"></Icon>重置</Button
>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" @click="onOK()"
><Icon custom="fa fa-fw fa-save"></Icon>保存</Button
>
</FormItem>
</iCol>
</Row>
</iForm>
</div>
</Modal>
<!-- LiuKexin 20210318 调整上间距 -->
<Side
:width="sideComponentWidth"
v-model="showSide"
style="
margin-top: 120px;
margin-right: 25px;
background-color: #fff;
height: auto;
"
>
<Card class="side-card">
<span slot="title">
<Icon :custom="'fa fa-' + sideComponentIcon"></Icon>
{{ sideComponentTitle }}
</span>
<component :is="sideComponent" :paraData="paraData"></component>
</Card>
</Side>
</template>
</div>
</div>
</template>
<script>
import SearchInput from '_c/search-input/searchInput'
import { getSystems, create, addorEdit, dele } from '@/api/system'
import Side from '@/views/components/side/side'
export default {
components: {
Side,
SearchInput,
},
data() {
const validateTitle = (rule, value, callback) => {
// lidecai 20200327 YZJ-2307 字符串校验不正确
let reg = /^[\u4E00-\u9FA5]+$/
if (value === '') {
callback(new Error('名称不能为空'))
} else {
if (!reg.test(value)) {
callback(new Error('请输入中文'))
}
callback()
}
}
const validateName = (rule, value, callback) => {
let ext = /(^[a-zA-Z]+$)/
if (value === '') {
callback(new Error('英文标识不能为空'))
} else {
if (!ext.test(value)) {
callback(new Error('请输入英文'))
}
callback()
}
}
return {
paraData: {},
showSide: false,
sideComponentTitle: '',
sideComponentIcon: '',
sideComponentWidth: 0,
sideComponent: null,
columns: [
//LiuKexin 20201225 字段样式
{
type: 'selection',
width: 55, //LiuKexin 20201216 宽度
align: 'center',
fixed: 'left',
},
{
title: '序号',
width: 50,
key: 'index',
type: 'index',
align: 'center',
fixed: 'left',
className: 'compact-cell',
},
{
title: '操作',
width: 80,
align: 'center',
slot: 'edit',
fixed: 'left',
className: 'compact-cell',
},
{
title: '名称',
width: 100,
key: 'name',
ellipsis: true,
tooltip: true,
resizable: true,
},
{
title: '中文名',
width: 120,
key: 'title',
ellipsis: true,
tooltip: true,
resizable: true,
},
{
title: '类型',
width: 100,
key: 'type',
ellipsis: true,
tooltip: true,
resizable: true,
},
{
title: 'URL',
width: 240,
key: 'url',
resizable: true, //LiuKexin 20210201 URL拖拽
render(h, params) {
/**Liukexin 20210118 render自定义文字提示 start */
return h('Tooltip',
{
props: {
placement: 'bottom-start',
transfer: true,
},
style: { width: '100%', marginTop: '8px' },
},
[
// LiuKexin 20210119 调整url的展示
h('p', { class: 'url-table-content'},params.row.url,),
[h('Button',{
props: {
type: 'text',
icon: 'md-open',
ghost: true,
},
style: {
color: '#2d8cf0',
padding:'0px',
float:'left'
},
on: {
click() {
window.open(params.row.url)
},
},
})],
[
h(
'span',
{
slot: 'content',
style: {
whiteSpace: 'normal',
wordBreak: 'break-all',
},
},
params.row.url
),
]
]
)
/**Liukexin 20210118 render自定义文字提示 end */
},
},
{
title: '服务',
width: 200,
key: 'service',
ellipsis: true,
tooltip: true,
resizable: true,
},
{
title: '密钥ID',
width: 300,
ellipsis: true,
tooltip: true,
resizable: true,
key: 'keyid',
},
{
title: '私钥',
width: 300,
ellipsis: true,
slot:'privatekey', //LiuKexin 20210118 插槽 自定义私钥
resizable: true,
key: 'privatekey',
},
{
title: '公钥',
width: 300,
ellipsis: true,
slot:'publickey', //LiuKexin 20210118 插槽 自定义公钥
resizable: true,
key: 'publickey',
},
{
title: '描述',
width: 200,
key: 'description',
ellipsis: true,
tooltip: true,
resizable: true,
},
],
// LiuKexin 20210118 私钥 公钥
fieldSlotList:[
{index:0,name:'privatekey'},
{index:1,name:'publickey'}
],
tableheight: 0,
title: '',
systems: [],
system: {
name: '',
title: '',
type: '',
url: '',
service: '',
keyid: '',
privatekey: '',
publickey: '',
description: '',
},
loading: false,
modal: false,
selection: [],
ruleValidate: {
name: [{ required: true, validator: validateName, trigger: 'blur' }],
title: [{ required: true, validator: validateTitle, trigger: 'blur' }],
type: [{ required: true, message: '类型不能为空', trigger: 'blur' }],
url: [{ required: true, message: 'URL不能为空', trigger: 'blur' }],
service: [{ required: true, message: '服务不能为空', trigger: 'blur' }],
keyid: [{ required: true, message: '密钥ID不能为空', trigger: 'blur' }],
privatekey: [
{ required: true, message: '私钥不能为空', trigger: 'blur' },
],
publickey: [
{ required: true, message: '公钥不能为空', trigger: 'blur' },
],
},
searchText: null,
typeList: [],
oldSystem: '',
}
},
methods: {
showMenuData(row) {
//显示对应菜单数据
this.paraData = {
tableheight: this.tableheight - 43,
id: row.id,
}
this.sideComponentTitle = '菜单展示'
this.sideComponentIcon = 'pencil-square-o'
this.sideComponentWidth = 1000
this.showSide = true
import('./menu').then((comp) => {
this.sideComponent = comp.default
})
},
clearSearch() {
this.getSystems()
},
searchByKeyword() {
this.getSystems()
},
initType() {
let data = this.systems
let typeList = []
data.forEach((element) => {
if (typeList.findIndex((type) => type.value === element.type) == -1) {
typeList.push({
value: element.type,
text: this.getTypeText(element.type) + '(' + element.type + ')',
})
}
})
this.typeList = { ...typeList }
},
getTypeText(type) {
let typeList = this.systems
.filter((item) => item.type === type)
.map((item) => item.title)
if (typeList.length === 2) {
return typeList[0]
}
const shoring = (s1, s2) => {
if (s1 < s2) return -1
return 1
}
return typeList.sort(shoring)[0]
},
createKey() {
create().then((res) => {
if (res.data === null || res.data.state !== 'ok') {
this.$Notice.error({ title: '提示', desc: '生成key失败' })
} else {
this.system.privatekey = res.data.privateKey
this.system.keyid = res.data.keyid
this.system.publickey = res.data.publicKey
}
})
},
addSystem() {
this.reset()
this.title = '添加'
this.sideComponentIcon = 'plus-circle' //LiuKexin 20201216 图标
this.modal = true
this.system.name = ''
this.system.title = ''
this.system.type = ''
this.system.url = ''
this.system.service = ''
this.system.keyid = ''
this.system.privatekey = ''
this.system.publickey = ''
this.system.description = ''
},
editSystem(row) {
this.title = '编辑'
this.sideComponentIcon = 'edit'
this.modal = true
this.oldSystem = row
this.system = Object.assign({}, row)
},
onOK() {
this.$refs.formValidate.validate((valid) => {
if (valid) {
addorEdit(this.system).then((res) => {
if (res.data && res.data.state === 'ok') {
this.$Notice.success({ title: '提示', desc: '保存成功' })
this.getSystems()
} else {
this.$Notice.error({ title: '提示', desc: res.data.msg })
}
})
this.modal = false
}
})
},
/**
* 对重置功能添加判断
* liuyimeng
* 2020-03-01
* **/
reset() {
if (this.title === '添加') {
this.$refs.formValidate.resetFields()
}
if (this.title === '编辑') {
this.system = Object.assign({}, this.oldSystem)
}
},
deleSystem() {
if (this.selection.length === 0) {
this.$Notice.warning({ title: '提示', desc: '至少选择一项' }) //xiaoying 20200717 YZJ-3932 信息类型不正确
return
}
this.$Modal.confirm({
title: '温馨提示',
content: '删除的数据不可恢复,是否确定删除?',
onOk: () => {
let ids = this.selection.map((item) => item.id)
let data = {
ids: ids.join(','),
}
dele(data).then((res) => {
if (res.data && res.data.state === 'ok') {
this.$Notice.success({ title: '提示', desc: '删除成功' })
this.getSystems()
} else {
this.$Notice.error({ title: '提示', desc: res.data.msg })
}
})
},
})
},
onSelect(selection) {
this.selection = selection
},
getSystems() {
let params = {
searchText: this.searchText,
}
getSystems(params).then((res) => {
if (res.data && res.data.state === 'ok') {
this.systems = res.data.systems
this.selection = []
this.initType()
}
})
},
},
mounted() {
this.tableheight = document.body.clientHeight - 192 //Liukexin 20210318 调整高度
this.getSystems()
},
}
</script>
<style>
.ivu-card-body {
padding: 0px;
}
.operate-button {
padding: 2px 7px;
width: 30px;
}
.compact-cell .ivu-table-cell {
padding-left: 5px;
padding-right: 5px;
}
.apply-app-outer {
height: 100%;
padding: 24px;
}
.apply-app-container {
height: 100%;
text-align: left;
background: #e9e9e9;
}
.apply-toolbar {
padding: 5px 10px;
padding-left: 4px;
background-color: #fff;
border: 1px solid #d7dde4;
font-size: 14px;
}
.form-editor {
position: relative;
padding: 16px;
}
.apply-server-search-icon {
width: 32px;
height: 32px;
line-height: 32px;
font-size: 16px;
text-align: center;
color: #808695;
position: absolute;
right: 13%;
z-index: 3;
}
/**LiuKexin 20201216 取消边框 */
.modalClass /deep/ .ivu-modal-body {
padding: 0px;
}
/**LiuKexin 20210118 内容过长 溢出部分省略号 */
.table-content {
width: 99%;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
}
/* Liukexin 20210109 调整url的展示 */
.url-table-content {
width: 160px;
float: left;
margin-top: 5px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-all;
}
/* LiuKexin 20210118 文字提示样式 */
.file-code-content {
width: 100%;
max-height: 60px;
overflow: auto;
}
/*滚动条样式*/
.file-code-content::-webkit-scrollbar {
width: 4px;
}
.file-code-content::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
background: #ccc;
}
.file-code-content::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
border-radius: 0;
background: rgba(0, 0, 0, 0.1);
}
</style>
<template>
<div>
<Row class="buttonClass">
<!-- <ButtonGroup> -->
<!-- LiuKexin 20201225 按钮样式 -->
<Button type="primary" style="padding:0 8px;padding-left:4px;" @click.stop="showModalMethods(null)">
<Icon custom="fa fa-plus-circle fa-fw" />添加
</Button>
<Button type="text" style="margin-left:8px;padding:0px" @click.stop="deleMenu">
<Icon custom="fa fa-trash fa-fw" style="color: red" />删除
</Button>
<!-- </ButtonGroup> -->
<SearchInput :value.sync="queryData" style="margin-left:7px;" @on-clear="initData" @on-click="initData" :width="260"/>
</Row>
<Row class="tableClass">
<Spin size="large" fix v-if="showSpin"></Spin>
<!-- durui 20201117 DAG-393 统一按钮和表单字体 去掉 size="small" -->
<Table
border
:height="paraData.tableheight"
:columns="columns"
:data="tableData"
style="border-left:0;"
@on-selection-change="onSelectionChange"
stripe
tooltip
ellipsis
>
<template slot-scope="{ row, index }" slot="operate">
<ButtonGroup>
<Button
class="operate-button"
@click.stop="showModalMethods(row, index)"
>
<Icon custom="fa fa-fw fa-edit"></Icon>
</Button>
</ButtonGroup>
</template>
</Table>
</Row>
<template>
<Modal v-model="showModal" width="660" :footer-hide="true" class="modalClass">
<p slot="header">
<span>
<Icon :custom="'fa fa-' + modalIcon"></Icon>
{{ modalTitle }}
</span>
</p>
<div class="form-editor">
<iForm :model="menuModal" :label-width="80" ref="modalRef" :rules="ruleValidate">
<Row>
<iCol span="12">
<FormItem label="名称" prop="title">
<iInput v-model="menuModal.title" placeholder="请输入中文"></iInput>
</FormItem>
</iCol>
<iCol span="12">
<FormItem label="英文标识" prop="name">
<iInput v-model="menuModal.name" placeholder="请输入英文"></iInput>
</FormItem>
</iCol>
<iCol span="24">
<FormItem label="访问路径" prop="path">
<iInput v-model="menuModal.path" placeholder="例如#/name1/name2"></iInput>
</FormItem>
</iCol>
<!-- 暂时不需要操作该字段 liuyimeng 2020-03-02 -->
<!-- <iCol span="12">
<FormItem label="目标" prop="target">
<iInput
v-model="menuModal.target"
placeholder="请输入该系统在新浏览器打开的页面"
></iInput>
</FormItem>
</iCol>-->
<iCol span="12">
<FormItem label="是否隐藏" prop="hidden">
<Select v-model="menuModal.hidden">
<Option
v-for="item in [{value:'0',label:'否'},{value:'1',label:'是'}]"
:value="item.value"
:key="item.value"
>{{ item.label }}</Option>
</Select>
</FormItem>
</iCol>
<iCol span="24">
<FormItem label="图标" prop="icon">
<iInput v-model="menuModal.icon" style="margin-bottom:2px;" placeholder="自定义菜单图标"></iInput>
<div class="lib-icons">
<span
v-for="icon in iconList"
:key="icon"
:class="{selected: icon==menuModal.icon}"
class="lib-icon"
@click="iconClick(icon)"
>
<!-- Liukexin 20201229 展示fa图标 -->
<Icon :custom="icon" size="24"></Icon>
</span>
</div>
</FormItem>
</iCol>
<iCol span="24">
<FormItem label="描述" prop="description">
<iInput v-model="menuModal.description" type="textarea" placeholder="请输入菜单描述"></iInput>
</FormItem>
</iCol>
<!-- LiuKexin 20201228 按钮靠右 -->
<iCol span="24" style="height:32px">
<FormItem class="button-toolbar" style="text-align: right;">
<Button @click="resetModal()" style="margin-left:8px">
<Icon custom="fa fa-refresh fa-fw"></Icon>重置</Button>&nbsp;&nbsp;
<Button type="primary" @click="saveMenu()"><Icon custom="fa fa-fw fa-save"></Icon>保存</Button>
</FormItem>
</iCol>
</Row>
</iForm>
</div>
</Modal>
</template>
</div>
</template>
<script>
import SearchInput from '_c/search-input/searchInput'
import { getMenuList, saveMenuData, deleteMenu } from '@/api/menu'
import { iconList, columns } from './static-data'
export default {
components: {
SearchInput
},
props: {
paraData: {
type: Object
}
},
data() {
/**
* 对必填项进行校验 liuyimeng 2020-03-02
* **/
const validateTitle = (rule, value, callback) => {
// lidecai 20200327 YZJ-2307 字符串校验不正确
let reg = /^[\u4E00-\u9FA5]+$/
if (value === '') {
callback(new Error('名称不能为空'))
} else {
if (!reg.test(value)) {
callback(new Error('请输入中文'))
}
callback()
}
}
const validateName = (rule, value, callback) => {
let ext = /(^[a-zA-Z]+$)/
if (value === '') {
callback(new Error('英文标识不能为空'))
} else {
if (!ext.test(value)) {
callback(new Error('请输入英文'))
}
callback()
}
}
const validatePath = (rule, value, callback) => {
if (value === '') {
callback(new Error('访问路径不能为空'))
} else {
callback()
}
}
return {
iconList,
/**
* 对必填项进行校验 liuyimeng 2020-03-02
* **/
ruleValidate: {
title: [{ required: true, validator: validateTitle, trigger: 'blur' }],
name: [{ required: true, validator: validateName, trigger: 'blur' }],
path: [{ required: true, validator: validatePath, trigger: 'blur' }],
hidden: [
{ required: true, message: '请选择是否隐藏菜单', trigger: 'blur' }
]
},
columns,
showSpin: false,
showModal: false,
modalIcon: '',
modalTitle: '',
menuModal: {
title: '',
name: '',
path: ''
},
tableSelectData: {},
tableData: [],
queryData: '',
oldMenuModal: ''
}
},
watch: {
'paraData.id'() {
this.initData()
},
queryData() {
if (!this.queryData) {
this.initData()
}
}
},
methods: {
iconClick(icon) {
//选择图标
this.menuModal.icon = icon
},
initData() {
//初始化table
this.showSpin = true
let params = {
sysId: this.paraData.id,
condStr: this.queryData
}
getMenuList(params).then(res => {
if (res.data.state == 'ok') {
let data = res.data.data
this.tableData = data
this.tableSelectData = []
}else {
this.$Notice.error({title:'提示',desc: res.data.msg})
}
this.showSpin = false
})
},
showModalMethods(row) {
//显示modal表单
this.resetModal()
if (row) {
this.oldMenuModal = row
this.menuModal = Object.assign({}, row)
this.menuModal.hidden = row.hidden ? '1' : '0'
this.modalTitle = '编辑'
this.modalIcon = 'edit'
} else {
this.modalTitle = '添加'
this.modalIcon = 'plus-circle'
this.resetModal()
}
this.showModal = true
},
resetModal() {
//重置Modal信息
if (this.modalTitle === '添加') {
this.$refs.modalRef.resetFields()
this.menuModal = {
id: null,
title: '',
name: '',
path: '',
hidden: '0',
description: '',
icon: 'fa fa-file', //LiuKexin 20201229 修改默认图标
target: null
}
}
if (this.modalTitle === '编辑') {
this.menuModal = Object.assign({}, this.oldMenuModal) //对重置按钮添加判断 liuyimeng 2020-03-01
}
},
saveMenu() {
//保存菜单
this.$refs.modalRef.validate(valid => {
if (valid) {
this.menuModal.systemId = this.paraData.id
let param = {
menu: this.menuModal
}
saveMenuData(param).then(res => {
this.$Notice[res.data.state == 'ok' ? 'success' : 'error']({
title:'提示',desc: res.data.msg
})
this.showModal = false
this.initData()
})
this.modal = false
}
})
},
deleMenu() {
//删除菜单
if (!this.tableSelectData.length) {
this.$Notice.warning({title:'提示',desc: '请至少选择一条数据!' })
return
}
this.$Modal.confirm({
title: '温馨提示',
content: '确定要删除吗?',
loading: true,
onOk: () => {
let params = {
ids: this.tableSelectData.map(item => item.id).join(',')
}
deleteMenu(params).then(res => {
this.$Notice[res.data.state == 'ok' ? 'success' : 'error']({
title:'提示',desc: res.data.msg
})
//删除成功后清空所选的数据 Liuyimeng 20200430 YZJ-3216
this.tableSelectData.length = 0
this.$Modal.remove()
this.initData()
})
}
})
},
onSelectionChange(row) {
//选择框
this.tableSelectData = Object.assign([], row)
}
},
mounted() {
this.initData()
}
}
</script>
<style>
.lib-icons {
padding: 5px;
border: 1px solid #dcdee2;
border-radius: 4px;
}
.lib-icons .selected {
border: 1px dotted #2d8cf0;
color: #2d8cf0;
}
/* LiuKexin 20201229 调整样式 */
.lib-icon {
display: inline-block;
padding:4px;
cursor: pointer;
border: 1px solid #fff;
border-radius: 4px;
height:34px;
width:7%;
text-align: center;
}
.ivu-card-bordered {
border: 0px;
}
.buttonClass {
border-top: 1px solid #d7dde4;
height: 43px;
line-height: 42px;
background-color: #fff;
padding-left: 4px;
}
.ivu-input-default {
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
}
.modalClass /deep/ .ivu-modal-body{
padding:0px
}
</style>
/**LiuKexin 20201229 更换图标 */
export const iconList = [
'fa fa-file',
'fa fa-mixcloud',
'fa fa-cloud-upload',
'fa fa-cloud-download',
'fa fa-file-archive-o',
'fa fa-archive',
'fa fa-search',
'fa fa-object-group',
'fa fa-trophy',
'fa fa-clipboard',
'fa fa-comments-o',
'fa fa-calendar-o',
'fa fa-heart',
'fa fa-id-card',
'fa fa-bookmark',
'fa fa-external-link',
'fa fa-lightbulb-o',
'fa fa-magic',
'fa fa-hand-pointer-o',
'fa fa-wrench',
'fa fa-area-chart',
'fa fa-bar-chart',
'fa fa-pie-chart',
'fa fa-line-chart',
'fa fa-microchip',
'fa fa-building',
'fa fa-cogs',
'fa fa-calendar',
'fa fa-university',
'fa fa-list-ul',
'fa fa-print',
'fa fa-table',
'fa fa-sitemap',
'fa fa-list-alt',
'fa fa-columns',
'fa fa-handshake-o',
'fa fa-database',
'fa fa-users',
'fa fa-user-secret',
'fa fa-trash',
'fa fa-file-text',
'fa fa-server',
'fa fa-globe',
'fa fa-crosshairs',
'fa fa-warning',
'fa fa-trello',
'fa fa-files-o',
'fa fa-modx',
'fa fa-chain-broken',
'fa fa-book',
'fa fa-folder-open-o',
'fa fa-shield',
'fa fa-newspaper-o',
'fa fa-home',
]
export const columns = [ //LiuKexin 20201225 文本省略号 提示
{
type: 'selection',
width: 50, //LiuKexin 20201216 列宽
align: 'center',
fixed: 'left',
className: 'compact-cell'
},
{
title: '操作',
width: 50,
align: 'center',
slot: 'operate',
fixed: 'left',
className: 'compact-cell'
},
{
title: '名称',
minWidth: 150,
key: 'title',
ellipsis:true,
tooltip:true,
resizable:true
},
{
title: '英文标识',
width: 150,
key: 'name',
ellipsis:true,
tooltip:true,
resizable:true
},
{
title: '访问路径',
width: 200,
key: 'path',
ellipsis:true,
tooltip:true,
resizable:true
},
{
title: '图标',
width: 150,
key: 'icon',
ellipsis:true,
tooltip:true,
resizable:true
},
/**
* 暂时不需要展示该字段 liuyimeng 2020-03-02
* **/
// {
// title: '目标',
// width: 100,
// key: 'target'
// },
{
title: '描述',
width: 250,
key: 'description',
ellipsis:true,
tooltip:true,
resizable:true
},
{
title: '是否隐藏',
width: 100,
key: 'hidden',
render(h, params) {
return h('div', [
params.row.hidden?'是':'否'
])
}
}
]
\ No newline at end of file
import Side from './side.vue'
export default Side
<template>
<transition
:css="false"
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
@leave="leave"
>
<div class="side" :style="sideStyle" v-show="visible" v-clickoutside="handleClose" ref="side">
<slot></slot>
</div>
</transition>
</template>
<script>
import Velocity from 'velocity-animate'
export default {
props: {
width: {
type: [Number, String],
required: true
},
value: {
type: Boolean,
default: false
}
},
watch: {
value() {
this.visible = this.value
}
},
data() {
return {
visible: this.show
}
},
computed: {
sideStyle() {
return {
width: typeof this.width == 'string' ? this.width : this.width + 'px',
right: (this.visible ? 0 : -this.width) + 'px'
}
}
},
methods: {
// handleClose() {
// this.visible = false
// this.$emit('input', this.visible)
// },
handleClose(e) {
//处理与其他组件冲突
let s = this.$refs['side'].getBoundingClientRect()
let domX = s.left
let domY = s.bottom
//如果鼠标在窗口内则不触发
if (domX < e.clientX && domY > e.clientY) {
return;
}
this.visible = false
this.$emit('input', this.visible)
},
beforeEnter(el) {
el.style.right = -this.width + 'px'
},
enter(el, done) {
Velocity(el, { right: '0px' }, { duration: 200, complete: done })
},
afterEnter(el) {},
leave(el, done) {
Velocity(
el,
{ right: -this.width + 'px' },
{ duration: 200, complete: done }
)
}
},
created() {
this.visible = this.value
}
}
</script>
<style>
.side {
position: absolute;
height: 100%;
top: 0px;
z-index: 1000;
box-shadow: -2px 0 6px -2px rgba(0, 0, 0, 0.2);
}
</style>
<template>
<div class="apply-app-outer">
<div class="apply-app-container">
<div class="apply-toolbar">
<Row span="24">
<Button @click.stop="addSystem" type="primary" style="padding:0 8px;">
<Icon custom="fa fa-fw fa-plus"></Icon>添加
</Button>
<Button @click="remove" type="text" style="margin-left:8px;padding:0px;">
<Icon custom="fa fa-trash fa-fw" aria-hidden="true" style="color: red"></Icon>删除
</Button>
<Divider type="vertical" />
<SearchInput
:value.sync="searchText"
@on-clear="clearSearch"
@on-click="searchByKeyword"
:width="260"
/>
</Row>
</div>
<div>
<!-- LiuKexin 20210318 调整高度 -->
<Table
border
tooltip="true"
:columns="columns"
:data="list"
:loading="loading"
:height="tableheight-70"
@on-selection-change="onSelect"
>
<template slot-scope="{ row, index }" slot="operate">
<ButtonGroup>
<Button
class="operate-button"
@click.stop="edit(row, index)"
>
<Icon custom="fa fa-fw fa-edit" title="编辑"></Icon>
</Button>
</ButtonGroup>
</template>
</Table>
<Page
style="float:left;padding:10px;width:100%;background-color:#fff"
:total="total"
:current="page_sum"
:page-size="page_size"
:page-size-opts="[10, 20, 50, 100]"
@on-change="handlePage"
@on-page-size-change="handelPageSizeChange"
size="small"
show-elevator
show-total
show-sizer
prev-text="上一页"
next-text="下一页"
/>
</div>
<template>
<!-- LiuKexin 20210318 调整间距和高度 -->
<Side :width="sideComponentWidth" v-model="showSide" style="margin-top:120px;margin-right:25px;background-color:#fff;height:auto;">
<Card :style="'height:' + (tableheight+20) + 'px'">
<span slot="title">
<Icon :custom="'fa fa-' + sideComponentIcon"></Icon>
{{sideComponentTitle}}
</span>
<component
:is="sideComponent"
:paraData="paraData"
@reload="reload"
></component>
</Card>
</Side>
</template>
</div>
</div>
</template>
<script>
import SearchInput from '_c/search-input/searchInput'
import { getList,remove } from '@/api/helper'
import Side from '@/views/components/side/side'
export default {
components: {
Side,
SearchInput
},
data() {
return {
paraData: {},
showSide: false,
sideComponentTitle: '',
sideComponentIcon: '',
sideComponentWidth: 0,
sideComponent: null,
columns: [
{
type: "selection",
width: 60,
align: "center",
},
{
title: "操作",
width: 70,
align: "center",
slot: "operate",
className: "compact-cell",
},
{
title: "名称",
minWidth: 150,
key: "name",
},
{
title: "文档类型",
width: 150,
key: "type_cn",
},
{
title: "描述",
width: 300,
key: "description",
},
],
tableheight: 0,
title: '',
list: [],
loading: false,
modal: false,
selection: [],
searchText: '',
page_size: 20,
page_sum: 1,
total:0,
isIE:false
}
},
methods: {
getTableData(pageSize) {
this.page_size = pageSize
this.getList();
},
reload(){
this.getList()
},
handelPageSizeChange(value) {
this.page_size = value;
this.page_sum = 1
this.getList();
},
handlePage(value) {
this.page_sum = value;
this.getList();
},
/**
* LiuKexin 20201123 修改删除,(1)添加警告框,(2)没有选择数据时给予提示
*/
remove(){
if(this.selection.length == 0){
this.$Notice.warning({title:'警告',desc:'请先选择数据'})
return
}
let content ="删除的数据不可恢复,确定要删除吗?"
this.showConfirmModal(this.selection, content).then(ids => {
remove(ids.join(",")).then(res => {
if (res.data && res.data.state === 'ok') {
this.$Notice.success({ title: '提示', desc: '删除成功!' })
/** LiuKexin 20201123 当前页全部删除后,页码停留在上一页 start*/
if(this.selection.length == this.list.length && this.page_sum > 1){
this.page_sum = this.page_sum - 1
}
if(this.selection.length == this.list.length && this.page_sum == 1){
this.page_sum = 1
}
/** LiuKexin 20201123 当前页全部删除后,页码停留在上一页 end*/
this.getList()
} else {
this.$Notice.error({
title: '提示',
desc:
res.data.msg != null
? res.data.msg
: '未知错误,请联系管理员解决',
})
}
this.$Modal.remove()
})
})
},
/**
* LiuKexin 20201123 删除添加弹出框
*/
showConfirmModal(selection, content) {
return new Promise(resolve => {
this.$Modal.confirm({
title: '警告',
content: content,
loading: true,
onOk: () => {
let ids = selection.map(item => {
return item.id
})
event.stopPropagation()
resolve(ids)
},
onCancel: () => {
event.stopPropagation()
}
})
})
},
clearSearch() {
this.getList()
},
searchByKeyword() {
this.page_sum = 1
this.getList()
},
addSystem(row) {
// this.paraData = {
// tableheight: this.tableheight-43,
// id: row.id
// }
this.sideComponentTitle = '添加帮助'
this.sideComponentIcon = 'pencil-square-o'
this.sideComponentWidth = 1000
this.showSide = true
this.paraData = null
import('./help-edit').then(comp => {
this.sideComponent = comp.default
})
},
edit(row) {
this.sideComponentTitle = '编辑帮助' //LiuKexn 20210315 名称
this.sideComponentIcon = 'edit'
this.sideComponentWidth = 1000
this.showSide = true
this.paraData = Object.assign({}, row)
import('./help-edit').then(comp => {
this.sideComponent = comp.default
})
},
onSelect(selection) {
this.selection = selection
},
getList() {
//LiuKexin 20201123 修改传递参数的格式
let params = {
searchText:this.searchText,
pageSize:this.page_size,
pageNumber:this.page_sum
}
getList(params).then(res => {
if (res.data && res.data.state === 'ok') {
let list = res.data.list.list
list.forEach(help => {
if (help.type == 0){
help["type_cn"] = "标准规范"
} else if (help.type == 1) {
help["type_cn"] = "使用手册"
} else if (help.type == 2) {
help["type_cn"] = "操作视频"
}
});
this.list = list
this.total = res.data.list.totalRow
this.selection = []
}
})
}
},
mounted() {
this.tableheight = document.body.clientHeight - 160
this.getList()
}
}
</script>
<style>
.ivu-card-body {
padding: 0px;
}
.operate-button {
padding: 2px 7px;
}
.compact-cell .ivu-table-cell {
padding-left: 5px;
padding-right: 5px;
}
.apply-app-outer {
height: 100%;
padding: 24px;
}
.apply-app-container {
height: 100%;
text-align: left;
background: #e9e9e9;
}
.apply-toolbar {
padding: 4px;
background-color: #fff;
border: 1px solid #d7dde4;
}
.form-editor {
position: relative;
padding: 16px;
}
.apply-server-search-icon {
width: 32px;
height: 32px;
line-height: 32px;
font-size: 16px;
text-align: center;
color: #808695;
position: absolute;
right: 13%;
z-index: 3;
}
.side-card{
height:800px;
}
</style>
<template>
<div class="apply-app-outer">
<div class="apply-app-container">
<div class="apply-toolbar">
<Row span="24">
<SearchInput
:value.sync="searchText"
@on-clear="clearSearch"
@on-click="searchByKeyword"
:width="260"
/>
</Row>
</div>
<div>
<!-- LiuKexin 20210318 调整高度 -->
<Table
border
tooltip="true"
:columns="columns"
:data="list"
:loading="loading"
:height="tableheight-70"
@on-selection-change="onSelect"
>
<template slot-scope="{ row, index }" slot="operate">
<ButtonGroup>
<Button
class="operate-button"
@click.stop="download(row, index)"
>
<span class="fa fa-download" title="下载文件"></span>
</Button>
</ButtonGroup>
</template>
</Table>
<Page
style="float:left;padding:10px;width:100%;background-color:#fff"
:total="total"
:current="page_sum"
:page-size="page_size"
:page-size-opts="[10, 20, 50, 100]"
@on-change="handlePage"
@on-page-size-change="handelPageSizeChange"
size="small"
show-elevator
show-total
show-sizer
prev-text="上一页"
next-text="下一页"
/>
</div>
</div>
</div>
</template>
<script>
import { getList } from '@/api/helper'
import SearchInput from '_c/search-input/searchInput'
export default {
components: {
SearchInput
},
data() {
return {
paraData: {},
showSide: false,
sideComponentTitle: '',
sideComponentIcon: '',
sideComponentWidth: 0,
sideComponent: null,
columns: [
{
title: '序号',
width: 50,
key: 'index',
type: 'index',
align: 'center',
className: 'compact-cell'
},
{
title: "操作",
width: 70,
align: "center",
slot: "operate",
className: "compact-cell",
},
{
title: "名称",
minWidth: 150,
key: "name",
},
{
title: "文档类型",
width: 150,
key: "type_cn",
},
{
title: "描述",
width: 300,
key: "description",
},
],
tableheight: 0,
title: '',
loading: false,
selection: [],
searchText: null,
list:[],
page_size: 20,
page_sum: 1,
total:0,
isIE:false
}
},
methods: {
getTableData(pageSize) {
this.page_size = pageSize
this.getList();
},
handelPageSizeChange(value) {
this.page_size = value;
this.page_sum = 1
this.getList();
},
handlePage(value) {
this.page_sum = value;
this.getList();
},
getList() {
let params = {
searchText:this.searchText,
pageSize:this.page_size,
pageNumber:this.page_sum
}
getList(params).then(res => {
if (res.data && res.data.state === 'ok') {
let list = res.data.list.list
list.forEach(help => {
if (help.type == 0){
help["type_cn"] = "标准规范"
} else if (help.type == 1) {
help["type_cn"] = "使用手册"
} else if (help.type == 2) {
help["type_cn"] = "操作视频"
}
});
this.list = list
this.total = res.data.list.totalRow
this.selection = []
}
})
},
/**
* Liukexin 20201120 下载操作手册
*/
download(row,index){
location.href = '/aserver/helper/downloadOperation?id=' + row.id
},
clearSearch() {
this.getList()
},
searchByKeyword() {
this.getList()
},
},
mounted() {
this.tableheight = document.body.clientHeight - 160
this.getList()
}
}
</script>
<style>
.ivu-card-body {
padding: 0px;
}
.operate-button {
padding: 2px 7px;
}
.compact-cell .ivu-table-cell {
padding-left: 5px;
padding-right: 5px;
}
.apply-app-outer {
height: 100%;
padding: 24px;
}
.apply-app-container {
height: 100%;
text-align: left;
background: #e9e9e9;
}
.apply-toolbar {
padding: 5px 10px;
background-color: #fff;
border: 1px solid #d7dde4;
}
.form-editor {
position: relative;
padding: 16px;
}
.apply-server-search-icon {
width: 32px;
height: 32px;
line-height: 32px;
font-size: 16px;
text-align: center;
color: #808695;
position: absolute;
right: 13%;
z-index: 3;
}
</style>
<template>
<div>
<template>
<Spin fix v-if="spinShow">
<Icon type="ios-loading" size="18" class="demo-spin-icon-load"></Icon>
<div>正在提交中,请稍等片刻...</div>
</Spin>
</template>
<Row class="head-toolbar">
<iCol>
<Button type="primary" style="padding:0 8px;" @click.stop="sub">
<!-- LiuKexin 20201123 修改确定图标 -->
<Icon custom="fa fa-save"></Icon>&nbsp;确定
</Button>
</iCol>
</Row>
<div class="content-toolbar">
<Form ref="helperFrom" :rules="helperValidate" :label-width="80">
<Row>
<iCol span="11">
<FormItem label="文件名称" prop="name" :maxlength="50">
<Input v-model.trim="helper.name" placeholder="请输入文件名称" />
</FormItem>
</iCol>
</Row>
<Row>
<iCol span="11">
<FormItem label="文件类别" prop="type" :maxlength="50">
<!-- <Input v-model.trim="helper.type" placeholder="请输入文件类别" /> -->
<RadioGroup v-model="helper.type">
<Radio :label="1">使用手册</Radio>
<Radio :label="0">标准规范</Radio>
<Radio :label="2">操作视频</Radio>
</RadioGroup>
</FormItem>
</iCol>
</Row>
<Row>
<iCol span="22">
<FormItem label="描述" prop="description">
<Input
v-model.trim="helper.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 5 }"
placeholder="请输入报表描述"
/>
</FormItem>
</iCol>
</Row>
<template v-if="isAdd">
<Row>
<iCol span="22">
<FormItem label="文件" prop="file">
<Upload
action
:before-upload="handleBeForeUpload"
show-upload-list
>
<Button icon="ios-cloud-upload-outline">{{
fileName == null ? '点击上传文件' : fileName
}}</Button>
</Upload>
</FormItem>
</iCol>
</Row>
</template>
</Form>
</div>
</div>
</template>
<script>
import { add, edit } from '@/api/helper'
export default {
props: {
paraData: Object,
},
data() {
return {
helper: {
file: '',
name: '',
type: 1,
description: '',
},
fileName: null,
helperValidate: {
name: [
{
validator: (rule, value, callback) => {
if (
this.helper.name == null ||
this.helper.name == undefined ||
this.helper.name.length == 0
) {
callback(new Error('文件名称不能为空'))
return
} else if (this.helper.name.length > 20) {
callback(new Error('文件名称不能超过20个字'))
return
}
callback()
},
required: true,
message: '文件名称不能为空',
trigger: 'blur',
},
],
type: [
{
validator: (rule, value, callback) => {
if (
this.helper.type == null ||
this.helper.type == undefined ||
this.helper.type.length == 0
) {
callback(new Error('文件类型不能为空'))
return
}
callback()
},
required: true,
message: '文件类型不能为空',
trigger: 'blur',
},
],
description: [
{
validator: (rule, value, callback) => {
if (this.helper.description.length > 50) {
callback(new Error('备注超出限制'))
return
}
callback()
},
trigger: 'blur',
},
],
file: [
{
validator: (rule, value, callback) => {
if (
this.helper.file == null ||
this.helper.file == undefined ||
this.helper.file == ''
) {
callback(new Error('请选择上传文件'))
return
}
callback()
},
required: true,
trigger: 'blur',
},
],
},
isAdd: true,
spinShow: false
}
},
computed: {},
mounted() {
if (this.paraData) {
this.isAdd = false
this.helper = Object.assign({}, this.paraData)
} else {
this.isAdd = true
this.helper = {
file: '',
name: '',
type: 1,
description: '',
}
}
},
methods: {
handleFormatError(file) {},
handleBeForeUpload(file) {
let size = file.size
if (size > 1024 * 1024 * 150) {
this.$Notice.error({ title: '提示', desc: '上传文件不能大于150M!' })
return false;
}
this.fileName = file.name
let fileFormat = this.fileName.substring(this.fileName.lastIndexOf('.'))
this.helper.file = file
return false
},
sub() {
// LiuKexin 20210315 描述为null
if(this.helper.description == null){
this.helper.description = ''
}
this.$refs.helperFrom.validate((valid) => {
this.backupValue = null
if (valid) {
// //对input框的值去除特殊字符 liuyimeng 20200403
// this.helper.name = this.helper.name.replace(
// /[ `~!@#$%^&*()_\-+=<>?:"{}|,.\\/;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g,
// ''
// )
// if (this.helper.description) {
// this.helper.description = this.helper.description.replace(
// /[ `~!@#$%^&*()_\-+=<>?:"{}|,.\\/;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g,
// ''
// )
// }
let param = new FormData() // 创建form对象
param.append('file', this.helper.file)
param.append('name', this.helper.name)
param.append('description', this.helper.description)
param.append('type', this.helper.type)
if (this.isAdd) {
this.add(param)
} else {
this.edit(this.helper)
}
}
})
},
edit(param) {
edit(param).then((res) => {
if (res.data && res.data.state === 'ok') {
this.$Notice.success({ title: '提示', desc: '修改成功!' })
this.$emit('reload')
} else {
this.$Notice.error({
title: '提示',
desc:
res.data.msg != null
? res.data.msg
: '未知错误,请联系管理员解决',
})
}
})
},
add(param) {
this.spinShow = true
add(param).then((res) => {
if (res.data && res.data.state === 'ok') {
this.$Notice.success({ title: '提示', desc: '添加成功!' })
//2020年11月23日 解决添加后页面不刷新 yangchengwu
this.helper = {
file: '',
name: '',
type: 1,
description: '',
}
this.fileName = null
this.spinShow = false
this.$emit('reload')
} else {
this.$Notice.error({
title: '提示',
desc:
res.data.msg != null
? res.data.msg
: '未知错误,请联系管理员解决',
})
}
this.$emit('close', true)
})
},
},
watch: {
paraData(newValue) {
if (newValue) {
this.isAdd = false
this.helper = Object.assign({}, newValue)
} else {
this.isAdd = true
this.helper = {
file: '',
name: '',
type: 1,
description: '',
}
}
},
},
}
</script>
<style>
.head-toolbar {
padding-top: 4px;
padding-bottom: 3px;
padding-left: 4px;
border-bottom: 1px solid #d7dde4;
background: #fff;
height: 100%;
}
.ivu-card-body {
padding: 0px;
}
.content-toolbar {
padding: 16px;
}
</style>
<template>
<div class="login-container">
<!-- Liukexin 20210120 调整背景 start -->
<div class="bg" :style="loginBg">
<div class="bg-title">
<!-- LiuKexin 20210204 调整图标大小不被挤压成椭圆 -->
<div style="width:64px;height:64px;float:left"><img style="width:100%;height:1005" src="archser.jpg" /></div>
<div class="header-app-name">数字档案室管理系统</div>
</div>
</div>
<!-- Liukexin 20210120 调整背景 end -->
<div class="login-card">
<!-- LiuKexin 20201201 调整标题的内容 start -->
<div class="login-card-title">
<!-- LiuKexin 202010120 图片 -->
<img class="login-img" src="login-box-bg.png" />
</div>
<!-- LiuKexin 20201201 调整标题的内容 end -->
<!-- LiuKexin 20210305 ModifyModal调整位置 -->
<ModifyModal class="login-card-content" :formData="form" v-if="showModifyModal" />
<div class="login-card-content" v-if="!showModifyModal">
<div class="login-card-productName">欢迎登录</div>
<div class="login-message-panel">
<div
class="login-message"
:class="{ success: isSuccess, error: isError }"
>
<span style="word-break:break-all;whiteSpace:normal">{{ message }}</span>
</div>
</div>
<div class="login-form">
<form>
<div class="login-form-item">
<div class="form-item-label">用户名</div>
<div class="form-item-input">
<input
type="text"
name="username"
class="form-input"
placeholder="请输入用户名"
v-model="form.username"
@input="handleUsernameInput"
@keyup.enter="handleEnter"
/>
</div>
<div class="form-item-tooltip" v-show="disabledUsername">
请输入用户名
</div>
</div>
<div class="login-form-item">
<div class="form-item-label">密码</div>
<div class="form-item-input">
<input
type="password"
name="password"
class="form-input"
placeholder="请输入密码"
v-model="form.password"
@input="handlePasswordInput"
@keyup.enter="handleEnter"
/>
</div>
<div class="form-item-tooltip" v-show="disabledPassword">
请输入密码
</div>
</div>
<!-- Liukexin 20210329 添加验证码 start -->
<div class="login-form-item">
<div class="form-item-label">校验码</div>
<div class="form-item-input">
<input
v-model="code"
placeholder="请输入验证码"
:maxlength="codeMax"
class="form-input"
style="width: 140px;float:left"
@input="compareCode"
@keyup.enter="handleEnter"
/>
<div class="form-item-tooltip" v-show="disabledCode && codeIsFalse">
验证码错误
</div>
<div class="form-item-tooltip" v-show="disabledCode && codeIsNull">
请输入验证码
</div>
<sidentify :identifyCode="identifyCode" style="float:left"></sidentify>
<Button type="text" style="padding:0;margin-top:10px;" @click="updateCode">换一换</Button>
</div>
</div>
<!-- Liukexin 20210329 添加验证码 end -->
<div class="login-form-item">
<div class="form-item-label"></div>
<div class="form-item-submit">
<input
type="button"
value="登录"
class="form-submit"
:class="{ disabled: disabledLogin }"
@click="handleLogin"
/>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import qs from 'qs'
import ModifyModal from './modify-modal'
// import { sm2 } from 'sm-crypto'
import {Encrypt} from './secert'
import { snVerify, ruleValidate, registered,getUserHome } from '@/api/login'
import Sidentify from './Sidentify.vue'
export default {
name: '',
components: {
ModifyModal,
Sidentify,
},
data() {
return {
showModifyModal: false,
loginBg: {
backgroundImage: 'url(login-bg.jpg)',
},
showLogin: false,
isSuccess: false,
isError: false,
message: '登录成功',
form: {
app: 'aserver',
callback: '/aserver/',
username: 'admin',
password: '',
},
disabledUsername: false,
disabledPassword: false,
disabledLogin: false,
isHaveHome:false, //LiuKexin 20210315 是否有设置首页
/** Liukexin 20210329 验证码 start */
identifyCode:"",
identifyCodes:"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", //随机生成验证码的范围
codeIsFalse: false, //验证码错误
codeIsNull: false, //验证码未填写
codeIsTrue: false, //验证码正确
codeMax: 4,
code: '',
disabledCode:false
/** Liukexin 20210329 验证码 end */
}
},
methods: {
/**
* Liukexin 20210329 生成验证码
*/
updateCode() {
this.identifyCode = "";
this.codeIsFalse = ""
this.codeIsNull = ""
this.code = ""
this.makeCode(this.identifyCodes,4);
},
/**
* Liukexin 20210329 随机生成4位验证码字符串
* */
makeCode (data, len) {
for (let i = 0; i < len; i++) {
this.identifyCode += data[this.randomNum(0, data.length - 1)]
}
},
/**
* Liukexin 20210329 随机数
*/
randomNum (min, max) {
max = max + 1
return Math.floor(Math.random() * (max - min) + min)
},
/**
* LiuKexin 20210329 校验验证码
*/
compareCode() {
if (this.code.length === 0) {
this.codeIsNull = true
this.codeIsFalse = false
this.codeIsTrue = false
this.disabledCode = true
return false
}
if (this.code.length > 0 && this.code.length < 4) {
this.codeIsFalse = true
this.codeIsTrue = false
this.codeIsNull = false
this.disabledCode = true
return false
}
if (!this.testCode()) {
this.codeIsFalse = true
this.codeIsTrue = false
this.codeIsNull = false
this.disabledCode = true
return false
} else if (this.testCode()) {
this.codeIsTrue = true
this.codeIsNull = false
this.codeIsFalse = false
this.disabledCode = false
return true
}
},
/**
* Liukexin 20210329 比较校验码的值
*/
testCode() {
if(this.identifyCode.toLowerCase() == this.code.toLowerCase()){
return true
} else {
return false
}
},
registered() {
this.$refs['snValidate'].validate((valid) => {
if (valid) {
registered(this.snValidate).then((res) => {
window.console.log(res)
if (res.data.state == 'ok') {
this.showLogin = true
} else {
this.$Notice.error({ title: '提示', desc: res.data.msg })
}
})
}
})
},
handleUsernameInput() {
if (this.form.username) {
this.disabledUsername = false
}
},
handlePasswordInput() {
if (this.form.password) {
this.disabledPassword = false
}
},
handleEnter() {
this.handleLogin()
},
handleLogin() {
if (this.disabledLogin) return
this.isSuccess = false
this.isError = false
if (this.valid()) {
this.disabledLogin = true
let params = Object.assign({}, this.form)
/**LiuKexin 20210311 根据用户名获取设置的首页 start */
this.isHaveHome=false
getUserHome({username:params.username}).then(url => {
if(url.data.state == 'ok'){
params.app = url.data.app
params.callback = url.data.callback
this.isHaveHome = true
} else {
params.app = this.form.app
params.callback = this.form.callback
this.isHaveHome = false
}
}).then(()=>{
/**LiuKexin 20210311 根据用户名获取设置的首页 end */
params.username = Encrypt(params.username);
params.password = Encrypt(params.password);
this.login(params)
.then((res) => {
if (res.data.state === 'ok') {
let verify = res.data.verify
if (verify) {
/**LiuKexin 20210311 区分默认首页和设置首页的callback start */
let callback = res.data.callback
if (callback) {
document.location.href = this.isHaveHome
?
callback.split("#")[0] + "?token="+ res.data.token+"#"+callback.split("#")[1]
:
callback + '?token=' + res.data.token
/**LiuKexin 20210311 区分默认首页和设置首页的callback end */
} else {
document.location.href =
this.form.callback + '?token=' + res.data.token
}
this.setSuccess()
} else {
this.form.token = res.data.token
this.showModifyModal = true
}
} else {
this.setError(res.data.msg ? res.data.msg : '登录失败')
}
this.disabledLogin = false
})
.catch(() => {
this.setError('登录失败')
this.disabledLogin = false
})
})
}
},
// encrypt(data) {
// let publicKey =
// '04272a7c8997d9883078acc011f450f88d54fdbbd6ddab950d7856a565182aad7e0b5da415f50e1d4433c2b633752dfa3bc04de879311091361db05584d972ff06'
// return sm2.doEncrypt(data, publicKey, 0)
// },
// encrypt(data) {
// let publicKey =
// '04272a7c8997d9883078acc011f450f88d54fdbbd6ddab950d7856a565182aad7e0b5da415f50e1d4433c2b633752dfa3bc04de879311091361db05584d972ff06'
// return sm2.doEncrypt(data, publicKey, 0)
// },
valid() {
let isValid = true
if (!this.form.username) {
this.disabledUsername = true
isValid = isValid && false
}
if (!this.form.password) {
this.disabledPassword = true
isValid = isValid && false
}
// LiuKexin 20210329 登录时校验验证码
if(!this.codeIsTrue){
isValid = this.compareCode()
}
return isValid
},
login({ app, callback, username, password }) {
return this.$http.post('/aserver/login', {
app,
callback,
username,
password,
})
},
setSuccess(msg = '登录成功') {
this.message = msg
this.isSuccess = true
this.isError = false
},
setError(msg = '登录失败') {
this.message = msg
this.isSuccess = false
this.isError = true
},
},
mounted() {
let para = qs.parse(document.location.search, { ignoreQueryPrefix: true })
if (para) {
this.form.app = para.app ? para.app : 'aserver'
this.form.callback = para.callback ? para.callback : '/aserver/'
}
this.updateCode() //LiuKexin 20210329 初始化验证码
},
}
</script>
<style>
html,
body,
.login-container {
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div,
input {
box-sizing: border-box;
color: #666;
}
/** LiuKexin 20201201 调整登录也背景图片的位置及大小 */
.bg {
height: 100%;
width: 100%;
position: absolute;
background-size: 80%;
background-position: 50%;
float: left;
}
/* Liukexin 20210126 调整样式 start */
.bg-title{
position:absolute;
width:35%;
left:15%;
top:10%;
}
.header-app-name{
padding:0 10px;
color: #5b6270;
/* color: #ffffff; */
border-radius: 3px;
font-size: 32px;
line-height: 64px;
}
/* Liukexin 20210126 调整样式 end */
.SnForm {
width: 80%;
margin: 0 12%;
margin-top: 5%;
}
.SnForm button {
width: 80%;
margin: 0 10%;
margin-top: 5%;
}
/** LiuKexin 20201201 调整登录页内容的 */
.login-card {
position: absolute;
opacity: 0.92;
float: right;
height: 60%;
width: 70%;
top: 20%;
left:15%;
border: 1px solid #e6e6e6;
border-radius: 6px;
background-color: rgb(250, 250, 253);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);
}
/**LiuKexin 20201201 修改标题 2021026 样式调整*/
.login-card-title {
position: absolute;
width: 50%;
height: 100%;
}
.login-img{
position: absolute;
width:80%;
top:30%;
left:10%;
}
/**Liukexin 20201201 数字档案室V2.0的样式 */
.login-card-productName {
font-size: 18px;
color: #000000;
text-align: center;
font-family: 'Microsoft YaHei';
}
/**Liukexin 20201207 调整登录框的位置 20210126 样式调整*/
.login-card-content {
position: absolute;
top: 6%; /**LiuKexin 20210329 调整间距 */
right: 10%;
width: 32%;
}
.login-message-panel {
height: 18px;
margin:5px 0;
}
.login-message {
position: relative;
text-align: center;
font-size: 14px;
}
.login-message span {
display: none;
}
.login-message.error span {
display: inline;
background-color: #ffefe6;
padding: 5px;
border: 1px solid #ffb08f;
border-radius: 5px;
}
.login-message.success span {
display: inline;
padding: 5px 10px;
border-radius: 5px;
border: 1px solid #8ce6b0;
background-color: #edfff3;
}
/* .login-form {
margin-top: 120px;
} */
.login-form-item {
padding: 8px 0px;
position: relative;
}
.login-form-item .form-item-label {
height: 28px;
padding-bottom: 8px;
}
.login-form-item input {
width: 100%;
height: 32px;
border-radius: 3px;
padding: 6px 10px;
margin: 0;
}
.login-form-item .form-input {
border: 1px solid #ccc;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.login-form-item .form-submit {
background: #006dde;
color: white;
border: 1px solid #0056b3;
cursor: pointer;
box-shadow: inset 0 -1px -1px rgba(0, 0, 0, 0.075);
}
.login-form-item .form-submit:hover {
background: #005dc0;
}
.form-item-submit .disabled {
background: #969696;
color: #d1d1d1;
border: 1px solid #868686;
cursor: pointer;
outline: 0;
box-shadow: inset 0 -1px -1px rgba(0, 0, 0, 0.075);
}
.form-item-submit .disabled:hover {
background: #969696;
border: 1px solid #868686;
cursor: default;
outline: 0;
box-shadow: inset 0 -1px -1px rgba(0, 0, 0, 0.075);
}
.form-item-label {
font-weight: bold;
}
.form-item-tooltip {
position: absolute;
bottom: -30px;
left: 100px;
background-color: #ffefe6;
padding: 5px 10px;
border: 1px solid #ffb08f;
border-radius: 5px;
box-shadow: 0 2px 5px #ffb08f;
}
.form-item-tooltip::before {
content: ' ';
position: absolute;
top: -6px;
left: 20%;
margin-top: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent #ffb08f transparent;
}
.form-item-tooltip::after {
content: ' ';
position: absolute;
top: -5px;
left: 20%;
margin-top: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent #ffefe6 transparent;
}
.form-item-remind {
font-weight: normal;
padding-top: 30px;
text-align: center;
}
</style>
<!--LiuKexin 20210329 生成图片验证码-->
<template>
<div class="s-canvas">
<canvas
id="s-canvas"
:width="contentWidth"
:height="contentHeight"
></canvas>
</div>
</template>
<script>
export default {
name: 'SIdentify',
props: {
identifyCode: {
type: String,
default: 'ASDF',
},
fontSizeMin: {
type: Number,
default: 24,
},
fontSizeMax: {
type: Number,
default: 32,
},
backgroundColorMin: {
type: Number,
default: 180,
},
backgroundColorMax: {
type: Number,
default: 240,
},
colorMin: {
type: Number,
default: 50,
},
colorMax: {
type: Number,
default: 160,
},
lineColorMin: {
type: Number,
default: 100,
},
lineColorMax: {
type: Number,
default: 200,
},
dotColorMin: {
type: Number,
default: 0,
},
dotColorMax: {
type: Number,
default: 255,
},
contentWidth: {
type: Number,
default: 100,
},
contentHeight: {
type: Number,
default: 32,
},
},
methods: {
// 生成一个随机数
randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
// 生成一个随机的颜色
randomColor(min, max) {
let r = this.randomNum(min, max)
let g = this.randomNum(min, max)
let b = this.randomNum(min, max)
return 'rgb(' + r + ',' + g + ',' + b + ')'
},
transparent() {
return 'rgb(255,255,255)'
},
drawPic() {
let canvas = document.getElementById('s-canvas')
let ctx = canvas.getContext('2d')
ctx.textBaseline = 'bottom'
// 绘制背景
ctx.fillStyle = this.randomColor(
this.backgroundColorMin,
this.backgroundColorMax
) //图形填充颜色设置
ctx.strokeStyle = this.randomColor(
this.backgroundColorMin,
this.backgroundColorMax
) //图形轮廓的颜色设置
ctx.fillRect(0, 0, this.contentWidth, this.contentHeight) //绘制一个填充的矩形 0 0 width height x起点 y起点 宽 高
ctx.strokeRect(0, 0, this.contentWidth, this.contentHeight) // 绘制一个矩形边框 0 0 width height x起点 y起点 宽 高
// 绘制文字
for (let i = 0; i < this.identifyCode.length; i++) {
this.drawText(ctx, this.identifyCode[i], i)
}
this.drawLine(ctx)
this.drawDot(ctx)
},
drawText(ctx, txt, i) {
ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)
ctx.font =
this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei border'
let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1)) -8
let y = this.randomNum(this.fontSizeMax, this.contentHeight+5)
var deg = this.randomNum(-10, 10)
// 修改坐标原点和旋转角度
ctx.translate(x, y)
ctx.rotate((deg * Math.PI) / 180)
ctx.fillText(txt, 0, 0)
// 恢复坐标原点和旋转角度
ctx.rotate((-deg * Math.PI) / 180)
ctx.translate(-x, -y)
},
drawLine(ctx) {
// 绘制干扰线
for (let i = 0; i < 5; i++) {
ctx.strokeStyle = this.randomColor(this.lineColorMin, this.lineColorMax)
ctx.beginPath()
ctx.moveTo(
this.randomNum(0, this.contentWidth),
this.randomNum(0, this.contentHeight)
)
ctx.lineTo(
this.randomNum(0, this.contentWidth),
this.randomNum(0, this.contentHeight)
)
ctx.stroke()
}
},
drawDot(ctx) {
// 绘制干扰点
for (let i = 0; i < 10; i++) {
ctx.fillStyle = this.randomColor(0, 255)
ctx.beginPath()
ctx.arc(
this.randomNum(0, this.contentWidth),
this.randomNum(0, this.contentHeight),
1,
0,
2 * Math.PI
)
ctx.fill()
}
},
},
watch: {
identifyCode() {
this.drawPic()
},
},
mounted() {
this.drawPic()
},
}
</script>
\ No newline at end of file
<template>
<div>
<!-- Liukexin 20210305 添加标题重置密码 -->
<div class="login-card-productName">重置密码</div>
<div class="login-message-panel">
<div
class="login-message"
:class="{ success: isSuccess, error: isError }"
>
<span>{{ message }}</span>
</div>
</div>
<!-- Liukexin 20210305 调整表单域标签的位置 ,会置于表单域顶部。-->
<Form
label-position="top"
:model="pwdData"
class="fromClass"
:rules="pwdValidate"
ref="userForm"
>
<Row class="login-form-item">
<iCol span="24">
<FormItem label="新密码" prop="newPwd"> <!--LiuKexin 20210305 去除:-->
<iInput
v-model.trim="pwdData.newPwd"
type="password"
placeholder="请输入密码"
style="width: 100%"
></iInput>
</FormItem>
</iCol>
</Row>
<Row class="login-form-item">
<iCol span="24">
<FormItem label="确认密码" prop="confirmPwd"> <!--LiuKexin 20210305 去除:-->
<iInput
v-model.trim="pwdData.confirmPwd"
type="password"
placeholder="请输入确认密码"
style="width: 100%"
></iInput>
</FormItem>
</iCol>
</Row>
<Row class="Savebutton">
<Button type="primary" @click="updatePwd" style="width: 100%"
><Icon custom="fa fa-fw fa-save"></Icon>保存</Button
>
</Row>
</Form>
</div>
</template>
<script>
import { update, verifyPassword } from '@/api/login'
// import { sm2 } from 'sm-crypto'
import 'iview/dist/styles/iview.css'
export default {
name: '',
props: {
formData: {
type: Object,
},
},
data() {
const validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('密码不能为空'))
} else {
verifyPassword({ password: value }).then((res) => {
if (res.data && res.data.state === 'ok') {
callback()
} else {
callback(new Error(res.data.msg))
}
})
}
}
const confirmPwd = (rule, value, callback) => {
if (value === '') {
callback(new Error('确认密码不能为空'))
} else if (this.pwdData.newPwd != value) {
callback(new Error('两次密码不一致'))
} else {
callback()
}
}
return {
message: '',
isSuccess: false,
isError: false,
confirmPwdMsg: false,
confirmMsg: '',
newMsg: '',
pwdData: {
newPwd: '',
confirmPwd: '',
},
pwdValidate: {
newPwd: [
{
required: true,
message: '密码不能为空',
trigger: 'blur',
},
{ validator: validatePass, trigger: 'blur' },
],
confirmPwd: [
{
required: true,
message: '确认密码不能为空',
trigger: 'blur',
},
{
validator: confirmPwd,
trigger: 'blur',
},
],
},
}
},
methods: {
//修改密码
updatePwd() {
this.isSuccess = false
this.isError = false
this.$refs.userForm.validate((valid) => {
if (!valid) {
return false
} else {
update(this.formData.username, this.pwdData.newPwd)
.then((res) => {
if (res.data.state === 'ok') {
let href =
this.formData.callback + '?token=' + this.formData.token
document.location.href = href
this.setSuccess()
} else {
this.setError(res.data.msg ? res.data.msg : '修改失败')
}
})
.catch(() => {
this.setError('修改失败')
})
}
})
},
// encrypt(data) {
// let publicKey =
// '04272a7c8997d9883078acc011f450f88d54fdbbd6ddab950d7856a565182aad7e0b5da415f50e1d4433c2b633752dfa3bc04de879311091361db05584d972ff06'
// return sm2.doEncrypt(data, publicKey, 0)
// },
// encrypt(data) {
// let publicKey =
// '04272a7c8997d9883078acc011f450f88d54fdbbd6ddab950d7856a565182aad7e0b5da415f50e1d4433c2b633752dfa3bc04de879311091361db05584d972ff06'
// return sm2.doEncrypt(data, publicKey, 0)
// },
setSuccess(msg = '修改成功') {
this.message = msg
this.isSuccess = true
this.isError = false
},
setError(msg = '修改失败') {
this.message = msg
this.isSuccess = false
this.isError = true
},
},
}
</script>
<style scoped>
.login-message {
position: absolute;
left: 50%;
transform: translate(-50%, -50%);
}
/**LiuKexin 20210305 '重置密码'样式 */
.login-card-productName {
font-size: 18px;
color: #000000;
text-align: center;
font-family: 'Microsoft YaHei';
}
/**LiuKexin 20210305 设置表单样式 */
.login-form-item{
padding-bottom: 8px;
height: 72px;
}
/**LiuKexin 20210305 保存按钮样式 */
.Savebutton{
height: 32px;
margin-top:48px;
}
</style>
import CryptoJS from 'crypto-js/crypto-js'
// 默认的 KEY 与 iv 如果没有给
const KEY = CryptoJS.enc.Utf8.parse("1234567890123456");
const IV = CryptoJS.enc.Utf8.parse('1234567890123456');
/**
* AES加密 :字符串 key iv 返回base64
*/
export function Encrypt(word, keyStr, ivStr) {
let key = KEY;
let iv = IV;
if (keyStr) {
key = CryptoJS.enc.Utf8.parse(keyStr);
iv = CryptoJS.enc.Utf8.parse(ivStr);
}
let srcs = CryptoJS.enc.Utf8.parse(word);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
}
/**
* AES 解密 :字符串 key iv 返回base64
*
* @return {string}
*/
export function Decrypt(word, keyStr, ivStr) {
let key = KEY;
let iv = IV;
if (keyStr) {
key = CryptoJS.enc.Utf8.parse(keyStr);
iv = CryptoJS.enc.Utf8.parse(ivStr);
}
let base64 = CryptoJS.enc.Base64.parse(word);
let src = CryptoJS.enc.Base64.stringify(base64);
let decrypt = CryptoJS.AES.decrypt(src, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.ZeroPadding
});
let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);
return decryptedStr.toString();
}
<template>
<div class="setting-outer">
<div class="setting-container">
<div class="setting-toolbar">
<Row>
<div style="width:80px;float:left;padding: 0 0 0 4px" class="leftButtonClass">
<Button type="primary" @click.stop="addSystem">
<Icon custom="fa fa-plus-circle fa-fw" aria-hidden="true"></Icon>添加
</Button>
</div>
<div align="left" style="padding: 0 8px 0 0" class="rightButtonClass">
<Button type="text" @click="deleSystem">
<Icon custom="fa fa-trash fa-fw" aria-hidden="true" style="color: red"></Icon>删除
</Button>
<Divider type="vertical" />
<SearchInput :value.sync="searchText" @on-clear="clearSearch" @on-click="searchByKeyword" :width="260"/>
</div>
</Row>
</div>
<div>
<Table
border
stripe
highlight-row
tooltip="true"
:columns="columns"
:data="configs"
:loading="loading"
:height="tableheight"
@on-selection-change="onSelect"
>
<template slot-scope="{ row, index }" slot="operate">
<Button
type="default"
@click.stop="editSystem(row, index)"
class="operate-button"
>
<Icon custom="fa fa-fw fa-edit" title="编辑"></Icon>
</Button>
</template>
</Table>
</div>
<Modal v-model="modal" width="660" :footer-hide="true">
<p slot="header">
<span>
<Icon :custom="'fa fa-' + sideComponentIcon"></Icon>
{{ title }}</span
>
</p>
<div>
<iForm
:model="config"
:label-width="80"
ref="formValidate"
:rules="ruleValidate"
>
<Row>
<iCol span="24">
<FormItem label="名称" prop="name">
<iInput
:disabled="isDis"
v-model="config.name"
placeholder="请输入系统名称"
></iInput>
</FormItem>
</iCol>
<iCol span="24">
<!-- LiuKexin 20200929 名称不是logo时 正常显示 -->
<FormItem label="值" prop="val" v-if="config.name != 'logo'">
<iInput
v-model="config.val"
placeholder="请输入配置值"
></iInput>
</FormItem>
<!-- liukexin 20200929 名称是logo时 添加上传按钮 start -->
<FormItem label="值" prop="val" v-if="config.name == 'logo'">
<iCol span="12">
<iInput
v-model="config.val"
placeholder="请输入配置值"
></iInput>
</iCol>
<iCol span="12">
<Button
style="font-size: 12px; margin-left: 16px"
@click.stop="changeLogo"
>
<Icon custom="fa fa-fw fa-picture-o"></Icon>上传</Button
>
</iCol>
</FormItem>
<!-- liukexin 20200929 名称是logo时 添加上传按钮 end -->
</iCol>
<iCol span="24">
<FormItem label="描述" prop="description">
<iInput v-model="config.description" type="textarea"></iInput>
</FormItem>
</iCol>
<!-- Liukexin 20201228 按钮靠右 -->
<iCol span="24" style="height:32px">
<FormItem class="button-toolbar" style="text-align: right">
<Button @click="reset()"><Icon custom="fa fa-refresh fa-fw"></Icon>重置</Button>
&nbsp;&nbsp;
<Button type="primary" @click="submit()"><Icon custom="fa fa-fw fa-save"></Icon>保存</Button>
</FormItem>
</iCol>
</Row>
<!-- LiuKexin 20200929 图片选择器 start-->
<template>
<input
name="file"
type="file"
ref="clearFile"
accept=".png"
enctype="multipart/form-data"
@change="importImageLogo"
id="fileForExcel"
style="display: none"
/>
</template>
<!-- LiuKexin 20200929 图片选择器 end-->
</iForm>
</div>
</Modal>
</div>
</div>
</template>
<script>
import SearchInput from '_c/search-input/searchInput'
import { getSettings, add, dele, findConfigList,changeSetting } from '@/api/setting'
export default {
components: {
SearchInput
},
watch: {
searchText() {
if(!this.searchText) {
this.searchByKeyword()
}
}
},
data() {
return {
columns: [
{
type: 'selection',
width: 55,
align: 'center',
className: 'compact-cell'
},
{
title: '操作',
width: 70,
className: 'compact-cell',
align: 'center',
slot: 'operate',
key: 'operate',
},
{
title: '名称',
width: 200,
key: 'name',
align: 'left',
ellipsis: true,
tooltip: true,
resizable: true
},
{
title: '值',
width: 250,
key: 'val',
align: 'left',
ellipsis: true,
tooltip: true,
resizable: true
},
{
title: '描述',
key: 'description',
align: 'left',
ellipsis: true,
tooltip: true,
resizable: true
}
],
sideComponentIcon: '',
title: '',
configs: [],
oldConfig:'',
config: {
id: 0,
name: '',
val: '',
description: ''
},
loading: false,
tableheight: 0,
modal: false,
selection: [],
searchText: null,
isDis: false, //Liukexin 20200929 名称是否置灰
file:null,
logoUrl:'',
ruleValidate: {
/**xiaoying 20200717 YZJ-3931 添加长度限制和特殊字符限制 start*/
name: [
{
validator: (rule, value, callback) => {
if (value == null || value == undefined || value.trim() == '') {
callback(new Error('名称不能为空'))
} else if ( value.length > 50 ) {
callback(new Error('名称的字数不能超过50'))
} else {
let reg = /[`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/im
if (reg.test(value)) {
callback(new Error("不允许输入特殊字符"));
}
callback()
}
},
required: true, trigger: 'blur'
}
],
val: [{
validator: (rule, value, callback) => {
if (value == null || value == undefined || value.trim() == '') {
callback(new Error('值不能为空'))
} else if ( value.length > 50 ) {
callback(new Error('值的字数不能超过50'))
} else {
let reg = /[`~!#$%^&*()_\-+=<>?"{}|,;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/im
if (reg.test(value)) {
callback(new Error("不允许输入特殊字符"));
}
callback()
}
},
required: true, trigger: 'blur'
}
/**xiaoying 20200717 YZJ-3931 添加长度限制和特殊字符限制 end*/
]
}
}
},
methods: {
/**
* LiuKexin 20200929 点击上传触发
*/
changeLogo() {
document.getElementById('fileForExcel').click()
},
/**
* LiuKexin 20200930 上传图片
* */
importImageLogo(e) {
this.file = e.target.files[0]
let _this = this
if (_this.file.size / 1024 > 300) {
_this.$Notice.warning({
title: '提示',
desc: '图片大小不能超过300Kb,请重新选择!',
})
_this.$store.state.logoUrl = this.logoUrl
_this.file = ''
return
}
if (_this.file.type.indexOf('png') > -1) {
_this.$Notice.success({ title: '提示', desc: '图片已上传,请点击保存' })
let reader = new FileReader()
reader.readAsDataURL(_this.file)
//图片转换成base64 回显
reader.onloadend = function () {
let newUrl = reader.result
_this.$store.state.logoUrl = newUrl
}
} else {
_this.$Notice.warning({
title: '提示',
desc: '图片格式只能选择png,请重新选择!',
})
_this.$store.state.logoUrl = this.logoUrl
_this.file = ''
}
},
searchByKeyword() {
let parame = {
searchText: this.searchText
}
findConfigList(parame).then(res => {
if (res.data && res.data.state === 'ok') {
this.configs = res.data.configs
}
})
},
clearSearch() {
this.getSettings()
},
addSystem() {
this.sideComponentIcon = 'plus'
this.title = '添加'
this.modal = true
this.config.id = 0
this.isDis = false //liukexin 20200929 添加名称不置灰
this.config.name = ''
this.config.val = ''
this.config.description = ''
this.$refs.formValidate.resetFields()//xiaoying 20200717 YZJ-3930 每次点击校验信息没有清空
},
deleSystem() {
if (this.selection.length === 0) {
this.$Notice.warning({ title:'提示',desc: '至少选择一项' })//xiaoying 20200717 YZJ-3929 提示类型不正确
return
}
this.$Modal.confirm({
title:'温馨提示',
content:'删除的数据不可恢复,是否确定删除?',
onOk: ()=>{
let ids = this.selection.map(item => item.id)
let data = {
ids: ids.join(',')
}
dele(data).then(res => {
if (res.data && res.data.state === 'ok') {
this.$Notice.success({ title:'提示',desc: '删除成功' })
this.getSettings()
} else {
this.$Notice.error({ title:'提示',desc: res.data.msg })
}
})
}
})
},
editSystem(row) {
this.sideComponentIcon = 'edit'
this.title = '编辑'
this.modal = true
this.isDis = true //liukexin 20200929 编辑名称置灰
this.oldConfig = Object.assign({}, row)
this.config.id = row.id
this.config.name = row.name
this.config.val = row.val
this.config.description = row.description
},
submit() {
this.$refs.formValidate.validate(valid => {
if (valid) {
add(this.config).then(res => {
if (res.data && res.data.state === 'ok') {
this.$Notice.success({ title:'提示',desc: res.data.ok })
// this.getSettings()
if (this.config.name == 'logo') {
let param = new FormData() // 创建form对象
param.append('file', this.file) //图片
changeSetting(param).then((setRes) => {
if (setRes.data && setRes.data.state !== 'ok') {
this.$Notice.error({ title: '提示', desc: setRes.data.msg })
this.$store.state.logoUrl = this.logoUrl
}
})
}
/** LiuKexin 20200930 保存图片 end */
this.getSettings()
} else {
this.$Notice.error({ title:'提示',desc: res.data.msg })
this.$store.state.logoUrl = this.logoUrl
}
})
this.modal = false
}
})
},
reset() {
if (this.title==='添加') {
this.$refs.formValidate.resetFields()
}
if (this.title==='编辑') {
this.config = Object.assign({}, this.oldConfig) //对重置按钮添加判断 liuyimeng 2020-03-01
/**Liukexin 20200930 重置logo start */
if(this.config.name == 'logo'){
this.$store.state.logoUrl = this.logoUrl
}
/**Liukexin 20200930 重置logo end */
}
},
onSelect(selection) {
this.selection = selection
},
getSettings() {
getSettings().then(res => {
if (res.data && res.data.state === 'ok') {
this.configs = res.data.configs
this.selection = []
}
})
}
},
mounted() {
this.tableheight = document.body.clientHeight - 180
this.logoUrl = this.$store.state.logoUrl
this.getSettings()
}
}
</script>
<style>
.setting-outer {
height: 100%;
padding: 24px;
}
.setting-container {
height: 100%;
text-align: left;
background: #e9e9e9;
}
.setting-toolbar {
border-right: 1px solid #dcdee2;
border-right-width: 1px;
border-right-style: solid;
border-right-color: rgb(220, 222, 226);
background: white;
height: 40px;
line-height: 39px;
}
.rightButtonClass .ivu-btn {
padding: 0px;
}
.leftButtonClass .ivu-btn {
padding: 0px 8px;
}
.operate-button {
padding: 2px 7px;
}
</style>
/*
* @Author: dongchaoguang
* @Date: 2021-09-10 12:12:59
* @LastEditors: dongchaoguang
* @LastEditTime: 2021-11-08 11:46:49
* @Description: file content
* @FilePath: \aserver-ui-15-nojc\vue.config.js
*/
const path = require('path')
const resolve = dir => {
return path.join(__dirname, dir)
}
// jc_sqjz/dzjz/aserver
const PUBLIC_PATH = process.env.NODE_ENV === 'production' ? '/' : '/'
module.exports = {
publicPath: PUBLIC_PATH,
// publicPath: '/aserver',
chainWebpack: config => {
config.resolve.alias
.set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components'))
.set('_c', resolve('src/components'))
config.module
.rule('iview')
.test(/iview.src.*?js$/)
.use('babel')
.loader('babel-loader')
.end()
},
transpileDependencies:[
'iview'
],
pages: {
index: {
// page 的入口
entry: 'src/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: '基础服务',
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
login: {
entry: 'src/main-login.js',
template: 'public/login.html',
filename: 'login.html',
tilte: '登录'
},
},
productionSourceMap: false,
devServer: {
proxy: {
'/aserver': {
target: 'http://localhost:11048/'
}
},
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment