Commit 45d69b70 by wangcong

初始化代码

parent 12ae5e13
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# lab
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
{
"name": "bill-runner-query",
"title": "查询定义执行",
"author": "qiaoyanqi",
"keywords": "bill-runner-query",
"company": "久其软件",
"type": false,
"version": "v0.1",
"license": "",
"description": "",
"icon":"icon16_DH_A_gms_chaxunpeizhi",
"data": {
"static": [
{"name": "vuex", "url": "static/lib/vuex.min.js"}
],
"app": {
"component": ["dist/app.bundle.js"]
},
"config": [
{
"title":"查询模板名称",
"key":"name",
"type": "text"
}
]
}
}
\ No newline at end of file
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
{
"name": "@rbc/bill-runner-query",
"version": "0.0.1",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build-dev": "vue-cli-service build --mode development",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"iviewex": "^2.6.26",
"nr.os.js": "^1.4.7",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
},
"files": [
"dist",
"src",
"app.config.json"
],
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.11"
}
}
<!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><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> 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 lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
import QueryRunner from './views/query-runner.vue'
export default {
app: QueryRunner
}
\ No newline at end of file
import Vue from 'vue'
import App from './App.vue'
import iview from 'iview'
import nros from 'nr.os.js'
import iviewex from 'iviewex'
import vuex from 'vuex'
// 公共资源目录,会引入nr.os提供的资源文件以供调试,打包时不会包含这些文件
import './public_library'
Vue.prototype.$utils = nros.SDK.utils
// 登录信息
const loginInfo = {
au_path: '/nvwa/login',
usr_name: 'admin',
usr_psw: 'admin',
tenant: '__default_tenant__'
}
const {
utils
} = nros.SDK
window.nros = nros
// const CRYPTO_KEY = lib.CryptoJS.enc.Utf8.parse('JIUQI/NEWREP/AES')
// const CRYPTO_VI = lib.CryptoJS.enc.Utf8.parse('JIUQI/NEWREP/AES')
// function encrypt (data) {
// return coding.enCoding(data,
// CRYPTO_KEY,
// { iv: CRYPTO_VI, mode: lib.CryptoJS.mode.CBC, padding: lib.CryptoJS.pad.ZeroPadding })
// }
// function decrypt (data) {
// return coding.deCoding(data,
// CRYPTO_KEY,
// { iv: CRYPTO_VI, mode: lib.CryptoJS.mode.CBC, padding: lib.CryptoJS.pad.ZeroPadding })
// }
const loginParam = {
username: loginInfo.usr_name,
pwd: loginInfo.usr_psw,
tenant: loginInfo.tenant,
encrypted: false
}
nros.restful.post(loginInfo.au_path, loginParam).then((res) => {
utils.setToken(res.token)
if (window._v) {
window._v.$Message.info(`${loginInfo.usr_name} 登录成功`)
} else {
console.log(`${loginInfo.usr_name} 登录成功`)
}
}).catch((res) => {
if (window._v) {
window._v.$Message.error(`<span>${loginInfo.usr_name} 登录失败</span><div style="margin-left: 15px;">info: ${res.data.message}</div>`)
} else {
console.log(`${loginInfo.usr_name} 登录失败`)
}
})
// 优先执行登录操作
setTimeout(() => {}, 1000)
// 保持原有app中调用名不变
Vue.prototype.$portalAPI = nros.event
Vue.use(nros.restful)
Vue.use(iview)
Vue.use(iviewex)
Vue.use(vuex)
// Vue.config.productionTip = false
window._v = new Vue({
render: h => h(App)
}).$mount('#app')
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* 此文件夹中的内容由nr.os提供
* 请不要自己随意修改此文件夹的内容
* 若有加依赖的需求请联系nr.os开发者
*/
import './nr-theme.css'
This source diff could not be displayed because it is too large. You can view the blob instead.
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
<template>
<gms-query
:templateName="config.name"
v-if="config.name"
:extrCondition="extrCondition"
></gms-query>
<p v-else>没有查询模板定义!</p>
</template>
<script>
export default {
props: {
config: {
type: Object,
default: function() {
return {};
},
},
},
data() {
return {
extrCondition: [],
};
},
mounted() {
if (this.config.param) {
this.extrCondition = this.config.param.fieldQueryRelation;
}
if(GMS.$hideContainer.$route.query && GMS.$hideContainer.$route.query.param){
this.extrCondition = GMS.$hideContainer.$route.query.param.fieldQueryRelation;
}
},
};
</script>
const path = require('path')
var config = {
configureWebpack: {
watch: false ,
entry: {
app: './src/main.build.js'
},
devtool: 'source-map',
output: {
library: 'portal_application',
libraryTarget: 'window',
libraryExport: 'default',
filename: 'app.bundle.js'
// filename: '[name].js'
},
module: {
rules: [
{
test: /\.(mp4|flv|swf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",
options: {
name: 'video/[name].[hash:7].[ext]'
}
},
{
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\?.*$/,
loader: 'url-loader?limit=8192'
}
]
},
externals: {
vue:'Vue',
jquery: 'jQuery',
['$']: 'jQuery',
'vue-router': 'VueRouter',
vuex: 'Vuex',
iview: 'iview',
iviewex: 'iviewex',
xlsx: 'XLSX'
},
resolve: {
alias: {
'@': path.resolve(__dirname,'src')
},
extensions: ['.js', '.vue']
}
},
chainWebpack: config => {
config.optimization.delete('splitChunks')
},
css: { extract: false }
}
lintOnSave: false,
module.exports = config
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
parserOptions: {
parser: 'babel-eslint'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-unused-vars': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# lab
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
# 思路
旧的实验室代码依赖过于老旧的webpack与vue等, 升级难度比较大, 配置适配nros也比较困难。 可以再尝试一下lab-old,但是如果还是不行,就从头开始用lab,
因为原来的代码实际上也用不了了, 因为控件库,和界面都要重写。
# TODO
1. 提取公用控件库
2. 调整lab结构,使得
a. 依赖控件库
b. 可以独立运行,可以对接原有功能树机制
c. 可以在gms-entry里面集成显示功能;
\ No newline at end of file
{
"name": "control-strategy",
"title": "控制策略配置",
"author": "王晓扬",
"keywords": "control-strategy",
"company": "久其软件",
"type": false,
"version": "v0.1",
"license": "",
"description": "",
"icon": "icon-_ZSYshujuluru",
"data": {
"static": [
{
"name": "vuex",
"url": "static/lib/vuex.min.js"
}
],
"app": {
"component": [
"dist/app.bundle.js"
]
},
"config": [
{
"title": "模版",
"key": "code",
"type": "array",
"dataSource": {
"api": "/api/define",
"titleColumn": "title",
"valueColumn": "code"
}
}
]
},
"expose": [
{
"title": "控制策略配置",
"icon": "",
"component": "ControlStrategy"
}
]
}
\ No newline at end of file
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "@rbc/control-strategy",
"version": "0.1.0",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build-dev": "vue-cli-service build --mode development",
"lint": "vue-cli-service lint"
},
"files": [
"dist",
"src",
"app.config.json"
],
"dependencies": {
"core-js": "^3.6.5",
"element-ui": "^2.15.6",
"iviewex": "^2.6.26",
"less-loader": "^5.0.0",
"nr.os.js": "^1.4.18",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"less": "^4.1.1",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.11"
}
}
<!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><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> 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>
import axios from 'axios'
// import nros from 'nr.os.js'
const service = axios.create({
baseURL: window.osConfig.baseUrl,
timeout: 120000
})
service.interceptors.request.use(config => {
config.headers.Authorization = window.nros.SDK.utils.getToken()
// console.log(window.nros)
return config
})
export default service
\ No newline at end of file
import request from '../axiosConfig'
const strategyGroup = '/v1/strategy-group'
export function getStrategyGroupTreeList() {
return request({
url: `${strategyGroup}/tree`,
method: 'GET'
})
}
export function createStrategyGroup(data) {
return request({
url: `${strategyGroup}`,
data: data,
method: 'POST'
})
}
export function updateStrategyGroup(data) {
return request({
url: `${strategyGroup}`,
data: data,
method: 'PUT'
})
}
export function deleteStrategyGroup(data) {
return request({
url: `${strategyGroup}/${data}`,
method: 'DELETE'
})
}
import request from '../axiosConfig'
const strategy = '/v1/strategy'
export function getBillDefine(data) {
return request({
url: `${strategy}/bill`,
method: 'GET'
})
}
export function getBillDefineField(data) {
return request({
url: `${strategy}/bill/field/${data}`,
method: 'GET'
})
}
export function getBillDefineId(data) {
return request({
url: `${strategy}/bill/billfield/${data}`,
method: 'GET'
})
}
export function getCombination(key, billDefineName, tableName) {
return request({
url: `${strategy}/combination/${key}/${billDefineName}/${tableName}`,
method: 'GET'
})
}
export function getStrategy(data) {
return request({
url: `${strategy}/get/${data}`,
method: 'GET'
})
}
export function getStrategyTreeList(data) {
return request({
url: `${strategy}/tree/${data}`,
method: 'GET'
})
}
export function createStrategy(data) {
return request({
url: `${strategy}`,
data: data,
method: 'POST'
})
}
export function updateStrategy(data) {
return request({
url: `${strategy}`,
data: data,
method: 'PUT'
})
}
export function deleteStrategy(data) {
return request({
url: `${strategy}/${data}`,
method: 'DELETE'
})
}
export function getExistFlag(data) {
return request({
url: `${strategy}/exist`,
data: data,
method: 'POST'
})
}
\ No newline at end of file
<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 lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
a {
font-weight: bold;
color: #2c3e50;
&.router-link-exact-active {
color: #42b983;
}
}
}
</style>
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
import Toolbar from './toolbar'
export default Toolbar
<template>
<div class="toolbar_frame" :class="{'system-1318': switchSystem()}">
<div class="toolbar-item" v-for="btn in toolbarData" :key="btn.key">
<Button
type="text"
@click="handleClick(btn.key)"
:disabled="checkDisabled(btn.key)"
>
{{ btn.name }}
<Icon type="ios-arrow-down" v-if="(btn.children && btn.children.length > 0) || btn.pattern === 'custom'"
@click.native.stop="handleArrowDownClick(btn.key)" :class="{ 'is-expanded': currentExpandKey === btn.key }" />
</Button>
<div class="custom-frame" v-if="btn.pattern === 'custom' && currentExpandKey === btn.key">
<slot :name="btn.key"></slot>
</div>
<div
v-if="btn.children && btn.children.length > 0 && currentExpandKey === btn.key && btn.pattern === 'multiple'"
class="toolbar-sub-items"
>
<div class="toolbar-group" v-for="(group, name, index) in btn.groups" :key="index">
<Checkbox
v-for="list in group"
:key="list.key"
v-model="list.checked"
@on-change="handleGroupCheckChange(btn, list)"
>{{list.name}}</Checkbox>
<div class="group-divider" v-if="Object.keys(btn.groups).length - 1 !== index"></div>
</div>
</div>
<ul
v-if="btn.children && btn.children.length > 0 && currentExpandKey === btn.key && btn.pattern !== 'multiple'"
class="toolbar-sub-items"
>
<li
class="sub-item"
v-for="item in btn.children"
:key="item.key"
@click="handleSubItemClick(btn, item)"
>
{{ item.switch ? item.replace : item.name }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'Toolbar',
props: {
buttons: {
type: Array,
required: true,
default () {
return []
}
},
disables: {
type: Array,
required: false,
default () {
return []
}
},
// 是否在点击菜单时展开子选项,默认点右侧下拉展开
expandOnClick: {
type: Boolean,
default: false
},
closeCurrentExpandKey: {
type: String
}
},
data () {
return {
toolbarData: [],
disableBtns: [],
currentExpandKey: '' // 当前正在展开的工具选项的key
}
},
methods: {
handleClick (key) {
if (this.expandOnClick) {
this.currentExpandKey = this.currentExpandKey ? '' : key
}
this.$emit(`on-${key}`)
},
hiddenSelectItems () {
this.currentExpandKey = ''
},
checkDisabled (name) {
if (this.disableBtns.includes(name)) {
return true
}
return false
},
disableButtons (names) {
names.forEach(name => {
if (!this.disableBtns.includes(name)) {
this.disableBtns.push(name)
}
})
},
enableButtons (names) {
names.forEach(name => {
const index = this.disableBtns.findIndex(item => item === name)
if (index !== -1) {
this.disableBtns.splice(index, 1)
}
})
},
// 除了这个数组中的按钮其他都禁用
disableButtonsExcept (names) {
this.disableBtns = []
this.buttons.forEach(item => {
if (!names.includes(item.key)) {
this.disableBtns.push(item.key)
}
})
},
switchSystem () {
if (this.$config && this.$config.systemName) {
return this.$config.systemName === '1318'
}
return false
},
handleArrowDownClick (key) {
this.currentExpandKey = this.currentExpandKey ? '' : key
},
handleSubItemClick (menu, item) {
if (menu.pattern === 'switch') {
item.switch = !item.switch
this.$emit(`on-${menu.key}`, item.key, item.switch)
} else {
this.$emit(`on-${menu.key}`, item.key)
}
this.currentExpandKey = ''
},
handleGroupCheckChange (menu, item) {
let checkes = {}
if (!checkes[item.group]) checkes[item.group] = []
Object.keys(menu.groups).forEach(name => {
checkes[name] = []
menu.groups[name].forEach(list => {
if (list.checked) checkes[name].push(list.key)
})
})
this.$emit(`on-${menu.key}`, checkes, item.key)
this.currentExpandKey = ''
}
},
created () {
this.disableBtns = JSON.parse(JSON.stringify(this.disables))
this.toolbarData = JSON.parse(JSON.stringify(this.buttons))
this.toolbarData.forEach(btn => {
if (btn.pattern === 'switch') {
btn.children.forEach(child => {
child.switch = false
child.replace = child.replace || '取消' + child.name
})
}
if (btn.pattern === 'multiple') {
btn.groups = {}
let lastChecked = null
btn.children.forEach(child => {
child.checked = child.checked || false
if (child.checked) lastChecked = child
let groupname = child.group || 'group'
if (!btn.groups[groupname]) {
btn.groups[groupname] = []
// btn.groups[groupname].checkes = []
// btn.groups[groupname].items = []
}
btn.groups[groupname].push(child)
// child.checked = false
})
if (lastChecked) {
this.handleGroupCheckChange(btn, lastChecked)
}
}
})
},
watch: {
buttons: {
handler (data) {
this.toolbarData = JSON.parse(JSON.stringify(data))
},
deep: true
},
closeCurrentExpandKey: {
handler (newVal, oldVal) {
this.currentExpandKey = this.currentExpandKey ? '' : newVal
},
deep: true
},
disables (disables) {
this.disableBtns = disables
}
}
}
</script>
<style lang="less">
@toolbarHeight: 32px;
@fontSize: 12px;
.toolbar_frame {
height: @toolbarHeight;
border-bottom: 1px solid #DDDDDD;
background-color: #fff;
display: flex;
flex-wrap: nowrap;
li {
list-style: none;
}
.toolbar-item {
float: left;
padding-top: 8px;
line-height: 16px;
height: @toolbarHeight;
position: relative;
.is-expanded {
transform: rotate(180deg);
}
.ivu-btn {
height: 16px;
line-height: 16px;
padding: 0 16px;
border-left: 1px solid #DDDDDD;
border-radius: 0;
box-shadow: none;
> span {
display: inline-block;
height: 14px;
line-height: 14px;
vertical-align: top;
font-size: @fontSize;
}
}
&:first-child {
.ivu-btn {
border-left: none;
}
}
.custom-frame {
min-width: 100%;
position: absolute;
left: 5px;
top: calc(100% + 2px);
z-index: 78;
margin-bottom: 0;
background-color: #ffffff;
box-shadow: 0 0 3px 0.5px;
}
.toolbar-sub-items {
min-width: 100%;
padding: 5px 0;
position: absolute;
left: 2px;
top: calc(100% + 2px);
z-index: 78;
margin-bottom: 0;
background-color: #ffffff;
box-shadow: 0 0 3px 0.5px;
// transition: height 5s;
.sub-item {
padding: 0 10px 0 30px;
font-size: 13px;
line-height: 30px;
white-space: nowrap;
display: flex;
align-items: center;
}
.sub-item:hover {
// background-color: #F4F9FF;
color: #4880FF;
cursor: pointer;
}
.toolbar-group {
padding: 5px 0;
.ivu-checkbox-wrapper {
display: block;
margin: 0;
height: 30px;
padding: 0 10px;
white-space: nowrap;
font-size: 13px;
font-weight: 400;
.ivu-checkbox {
margin-top: -2px;
}
}
.ivu-checkbox-wrapper:hover {
color: #4880FF;
}
.group-divider {
// padding-left: 10px;
margin: 0 10px 5px 10px;
border-bottom: 1px solid #DDDDDD;
}
}
}
}
}
.toolbar_frame.system-1318 {
height: 37px;
border-bottom: 2px solid #BEC5C8;
background-color: transparent;
background: url("./assets/img/toorbar_background.png") left;
.toolbar-item {
height: 37px;
padding: 10px 0;
.ivu-btn {
border-left: 1px solid #91999D;
background-color: transparent;
// &:first-child {
// border-left: none;
// }
span {
font-size: 14px;
// color: #16344C;
}
}
.ivu-btn:disabled {
span {
color: #797b7e;
}
}
&:first-child {
.ivu-btn {
border-left: none;
}
}
.toolbar-sub-items {
background-color: #D9DCE0;
.sub-item {
color: #1B3E59;
}
.sub-item:hover {
// background-color: rgba(60,194,172,0.12);
color: #3CC2AC;
}
.toolbar-group {
.ivu-checkbox-wrapper {
color: #1B3E59;
.ivu-checkbox {
.ivu-checkbox-inner {
border-color: #1B3E59;
}
}
}
.ivu-checkbox-wrapper:hover {
// color: #3CC2AC;
}
.ivu-checkbox-wrapper-checked {
.ivu-checkbox {
.ivu-checkbox-inner {
border-color: #3CC2AC;
}
}
}
.group-divider {
border-color: #1B3E59;
}
}
}
}
}
</style>
import Toolbar from './toolbar'
export default Toolbar
<template>
<div class="toolbar_frame" :class="{'system-1318': switchSystem()}">
<div class="toolbar-item" v-for="btn in toolbarData" :key="btn.key">
<Button
type="text"
@click="handleClick(btn.key)"
:disabled="checkDisabled(btn.key)"
>
{{ btn.name }}
<Icon type="ios-arrow-down" v-if="(btn.children && btn.children.length > 0) || btn.pattern === 'custom'"
@click.native.stop="handleArrowDownClick(btn.key)" :class="{ 'is-expanded': currentExpandKey === btn.key }" />
</Button>
<div class="custom-frame" v-if="btn.pattern === 'custom' && currentExpandKey === btn.key">
<slot :name="btn.key"></slot>
</div>
<div
v-if="btn.children && btn.children.length > 0 && currentExpandKey === btn.key && btn.pattern === 'multiple'"
class="toolbar-sub-items"
>
<div class="toolbar-group" v-for="(group, name, index) in btn.groups" :key="index">
<Checkbox
v-for="list in group"
:key="list.key"
v-model="list.checked"
@on-change="handleGroupCheckChange(btn, list)"
>{{list.name}}</Checkbox>
<div class="group-divider" v-if="Object.keys(btn.groups).length - 1 !== index"></div>
</div>
</div>
<ul
v-if="btn.children && btn.children.length > 0 && currentExpandKey === btn.key && btn.pattern !== 'multiple'"
class="toolbar-sub-items"
>
<li
class="sub-item"
v-for="item in btn.children"
:key="item.key"
@click="handleSubItemClick(btn, item)"
>
{{ item.switch ? item.replace : item.name }}
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
name: 'Toolbar',
props: {
buttons: {
type: Array,
required: true,
default () {
return []
}
},
disables: {
type: Array,
required: false,
default () {
return []
}
},
// 是否在点击菜单时展开子选项,默认点右侧下拉展开
expandOnClick: {
type: Boolean,
default: false
},
closeCurrentExpandKey: {
type: String
}
},
data () {
return {
toolbarData: [],
disableBtns: [],
currentExpandKey: '' // 当前正在展开的工具选项的key
}
},
methods: {
handleClick (key) {
if (this.expandOnClick) {
this.currentExpandKey = this.currentExpandKey ? '' : key
}
this.$emit(`on-${key}`)
},
hiddenSelectItems () {
this.currentExpandKey = ''
},
checkDisabled (name) {
if (this.disableBtns.includes(name)) {
return true
}
return false
},
disableButtons (names) {
names.forEach(name => {
if (!this.disableBtns.includes(name)) {
this.disableBtns.push(name)
}
})
},
enableButtons (names) {
names.forEach(name => {
const index = this.disableBtns.findIndex(item => item === name)
if (index !== -1) {
this.disableBtns.splice(index, 1)
}
})
},
// 除了这个数组中的按钮其他都禁用
disableButtonsExcept (names) {
this.disableBtns = []
this.buttons.forEach(item => {
if (!names.includes(item.key)) {
this.disableBtns.push(item.key)
}
})
},
switchSystem () {
if (this.$config && this.$config.systemName) {
return this.$config.systemName === '1318'
}
return false
},
handleArrowDownClick (key) {
this.currentExpandKey = this.currentExpandKey ? '' : key
},
handleSubItemClick (menu, item) {
if (menu.pattern === 'switch') {
item.switch = !item.switch
this.$emit(`on-${menu.key}`, item.key, item.switch)
} else {
this.$emit(`on-${menu.key}`, item.key)
}
this.currentExpandKey = ''
},
handleGroupCheckChange (menu, item) {
let checkes = {}
if (!checkes[item.group]) checkes[item.group] = []
Object.keys(menu.groups).forEach(name => {
checkes[name] = []
menu.groups[name].forEach(list => {
if (list.checked) checkes[name].push(list.key)
})
})
this.$emit(`on-${menu.key}`, checkes, item.key)
this.currentExpandKey = ''
}
},
created () {
this.disableBtns = JSON.parse(JSON.stringify(this.disables))
this.toolbarData = JSON.parse(JSON.stringify(this.buttons))
this.toolbarData.forEach(btn => {
if (btn.pattern === 'switch') {
btn.children.forEach(child => {
child.switch = false
child.replace = child.replace || '取消' + child.name
})
}
if (btn.pattern === 'multiple') {
btn.groups = {}
let lastChecked = null
btn.children.forEach(child => {
child.checked = child.checked || false
if (child.checked) lastChecked = child
let groupname = child.group || 'group'
if (!btn.groups[groupname]) {
btn.groups[groupname] = []
// btn.groups[groupname].checkes = []
// btn.groups[groupname].items = []
}
btn.groups[groupname].push(child)
// child.checked = false
})
if (lastChecked) {
this.handleGroupCheckChange(btn, lastChecked)
}
}
})
},
watch: {
buttons: {
handler (data) {
this.toolbarData = JSON.parse(JSON.stringify(data))
},
deep: true
},
closeCurrentExpandKey: {
handler (newVal, oldVal) {
this.currentExpandKey = this.currentExpandKey ? '' : newVal
},
deep: true
},
disables (disables) {
this.disableBtns = disables
}
}
}
</script>
<style lang="less">
@toolbarHeight: 32px;
@fontSize: 12px;
.toolbar_frame {
height: @toolbarHeight;
border-bottom: 1px solid #DDDDDD;
background-color: #fff;
display: flex;
flex-wrap: nowrap;
li {
list-style: none;
}
.toolbar-item {
float: left;
padding-top: 8px;
line-height: 16px;
height: @toolbarHeight;
position: relative;
.is-expanded {
transform: rotate(180deg);
}
.ivu-btn {
height: 16px;
line-height: 16px;
padding: 0 16px;
border-left: 1px solid #DDDDDD;
border-radius: 0;
box-shadow: none;
> span {
display: inline-block;
height: 14px;
line-height: 14px;
vertical-align: top;
font-size: @fontSize;
}
}
&:first-child {
.ivu-btn {
border-left: none;
}
}
.custom-frame {
min-width: 100%;
position: absolute;
left: 5px;
top: calc(100% + 2px);
z-index: 78;
margin-bottom: 0;
background-color: #ffffff;
box-shadow: 0 0 3px 0.5px;
}
.toolbar-sub-items {
min-width: 100%;
padding: 5px 0;
position: absolute;
left: 2px;
top: calc(100% + 2px);
z-index: 78;
margin-bottom: 0;
background-color: #ffffff;
box-shadow: 0 0 3px 0.5px;
// transition: height 5s;
.sub-item {
padding: 0 10px 0 30px;
font-size: 13px;
line-height: 30px;
white-space: nowrap;
display: flex;
align-items: center;
}
.sub-item:hover {
// background-color: #F4F9FF;
color: #4880FF;
cursor: pointer;
}
.toolbar-group {
padding: 5px 0;
.ivu-checkbox-wrapper {
display: block;
margin: 0;
height: 30px;
padding: 0 10px;
white-space: nowrap;
font-size: 13px;
font-weight: 400;
.ivu-checkbox {
margin-top: -2px;
}
}
.ivu-checkbox-wrapper:hover {
color: #4880FF;
}
.group-divider {
// padding-left: 10px;
margin: 0 10px 5px 10px;
border-bottom: 1px solid #DDDDDD;
}
}
}
}
}
.toolbar_frame.system-1318 {
height: 37px;
border-bottom: 2px solid #BEC5C8;
background-color: transparent;
background: url("./assets/img/toorbar_background.png") left;
.toolbar-item {
height: 37px;
padding: 10px 0;
.ivu-btn {
border-left: 1px solid #91999D;
background-color: transparent;
// &:first-child {
// border-left: none;
// }
span {
font-size: 14px;
// color: #16344C;
}
}
.ivu-btn:disabled {
span {
color: #797b7e;
}
}
&:first-child {
.ivu-btn {
border-left: none;
}
}
.toolbar-sub-items {
background-color: #D9DCE0;
.sub-item {
color: #1B3E59;
}
.sub-item:hover {
// background-color: rgba(60,194,172,0.12);
color: #3CC2AC;
}
.toolbar-group {
.ivu-checkbox-wrapper {
color: #1B3E59;
.ivu-checkbox {
.ivu-checkbox-inner {
border-color: #1B3E59;
}
}
}
.ivu-checkbox-wrapper:hover {
// color: #3CC2AC;
}
.ivu-checkbox-wrapper-checked {
.ivu-checkbox {
.ivu-checkbox-inner {
border-color: #3CC2AC;
}
}
}
.group-divider {
border-color: #1B3E59;
}
}
}
}
}
</style>
/**
* 最后打包发布的时候会使用此文件,请将main.js中的引用部分转移到这里
* 不要写入公共依赖文件夹,不要引入iview,iviewex和vuex
*/
// import App from './App.vue'
// import {rserInit} from 'rser-basis-app' //默认执行一次basis的入口
import Vue from 'vue'
import { ControlStrategy } from './views/index';
// import vaCommon from '@va/common';
// import '@va/common/lib/css/main.css';
// // import 'rser-basis-app/src/public_library/ago.css';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
// rserInit();
// Vue.use(vaCommon)
Vue.use(ElementUI)
// Vue.prototype.$vaRewrite = {
// get: (url) => {
// let urlPre = ''
// if (window.osConfig.baseUrl) {
// urlPre = window.osConfig.baseUrl
// }
// if (url.indexOf('/api/') === 0) {
// urlPre = urlPre + url.substring(4)
// } else {
// urlPre = urlPre + url
// }
// return urlPre
// }
// }
// 在此处引入vuex和router,将下面导出对象改为{app: App, store: store, routes: router}
// import store from './Store'
// export default { app: App }
//安装mcon.js中的内容
window.$collector = window.GMS.getContext().getCollector();
window.GMS.getContext().getCollector().updateElements(require.context('./', true, /mcon\.js$/));
export default {
ControlStrategy: {
app: ControlStrategy
},
}
\ No newline at end of file
import Vue from 'vue'
import App from './App.vue'
import iview from 'iview'
import nros from 'nr.os.js'
import iviewex from 'iviewex'
import vuex from 'vuex'
// 公共资源目录,会引入nr.os提供的资源文件以供调试,打包时不会包含这些文件
import './public_library'
Vue.prototype.$utils = nros.SDK.utils
// 登录信息
const loginInfo = {
au_path: '/nvwa/login',
usr_name: 'admin',
usr_psw: 'admin',
tenant: '__default_tenant__'
}
const {
utils
} = nros.SDK
window.nros = nros
// const CRYPTO_KEY = lib.CryptoJS.enc.Utf8.parse('JIUQI/NEWREP/AES')
// const CRYPTO_VI = lib.CryptoJS.enc.Utf8.parse('JIUQI/NEWREP/AES')
// function encrypt (data) {
// return coding.enCoding(data,
// CRYPTO_KEY,
// { iv: CRYPTO_VI, mode: lib.CryptoJS.mode.CBC, padding: lib.CryptoJS.pad.ZeroPadding })
// }
// function decrypt (data) {
// return coding.deCoding(data,
// CRYPTO_KEY,
// { iv: CRYPTO_VI, mode: lib.CryptoJS.mode.CBC, padding: lib.CryptoJS.pad.ZeroPadding })
// }
const loginParam = {
username: loginInfo.usr_name,
pwd: loginInfo.usr_psw,
tenant: loginInfo.tenant,
encrypted: false
}
nros.restful.post(loginInfo.au_path, loginParam).then((res) => {
utils.setToken(res.token)
if (window._v) {
window._v.$Message.info(`${loginInfo.usr_name} 登录成功`)
} else {
console.log(`${loginInfo.usr_name} 登录成功`)
}
}).catch((res) => {
if (window._v) {
window._v.$Message.error(`<span>${loginInfo.usr_name} 登录失败</span><div style="margin-left: 15px;">info: ${res.data.message}</div>`)
} else {
console.log(`${loginInfo.usr_name} 登录失败`)
}
})
// 优先执行登录操作
setTimeout(() => {}, 1000)
// 保持原有app中调用名不变
Vue.prototype.$portalAPI = nros.event
Vue.use(nros.restful)
Vue.use(iview)
Vue.use(iviewex)
Vue.use(vuex)
// Vue.config.productionTip = false
window._v = new Vue({
render: h => h(App)
}).$mount('#app')
// import gmsview from '@gms/gmsview';
// export default gmsview.Bill.mcon;
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
/**
* 此文件夹中的内容由nr.os提供
* 请不要自己随意修改此文件夹的内容
* 若有加依赖的需求请联系nr.os开发者
*/
import './nr-theme.css'
This source diff could not be displayed because it is too large. You can view the blob instead.
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
},
mutations: {
},
actions: {
},
modules: {
}
})
import ControlStrategy from './control-strategy.vue'
export {
ControlStrategy
}
\ No newline at end of file
const path = require('path')
var config = {
configureWebpack: {
watch: false ,
entry: {
app: './src/main.build.js'
},
devtool: 'source-map',
output: {
library: 'portal_application',
libraryTarget: 'window',
libraryExport: 'default',
filename: 'app.bundle.js'
// filename: '[name].js'
},
module: {
rules: [
{
test: /\.(mp4|flv|swf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",
options: {
name: 'video/[name].[hash:7].[ext]'
}
},
{
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\?.*$/,
loader: 'url-loader?limit=8192'
}
]
},
externals: {
vue:'Vue',
jquery: 'jQuery',
['$']: 'jQuery',
'vue-router': 'VueRouter',
vuex: 'Vuex',
iview: 'iview',
iviewex: 'iviewex',
xlsx: 'XLSX'
},
resolve: {
alias: {
'@': path.resolve(__dirname,'src')
},
extensions: ['.js', '.vue']
}
},
chainWebpack: config => {
config.optimization.delete('splitChunks')
},
css: { extract: false }
}
lintOnSave: false,
module.exports = config
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
parserOptions: {
parser: 'babel-eslint'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-unused-vars': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
}
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# lab
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
# 思路
旧的实验室代码依赖过于老旧的webpack与vue等, 升级难度比较大, 配置适配nros也比较困难。 可以再尝试一下lab-old,但是如果还是不行,就从头开始用lab,
因为原来的代码实际上也用不了了, 因为控件库,和界面都要重写。
# TODO
1. 提取公用控件库
2. 调整lab结构,使得
a. 依赖控件库
b. 可以独立运行,可以对接原有功能树机制
c. 可以在gms-entry里面集成显示功能;
\ No newline at end of file
{
"name": "file-management",
"title": "文件管理",
"author": "yy",
"keywords": "file-management",
"company": "久其软件",
"type": false,
"version": "v0.1",
"license": "",
"description": "",
"icon": "icon-_ZSYshujuluru",
"data": {
"static": [
{
"name": "vuex",
"url": "static/lib/vuex.min.js"
}
],
"app": {
"component": [
"dist/app.bundle.js"
]
},
"config": [
{
"title": "模版",
"key": "code",
"type": "array",
"multiple": true,
"dataSource": {
"api": "/rbcfunc/metadata/resource/queryview",
"titleColumn": "title",
"valueColumn": "name"
}
}
]
},
"expose": [
{
"title": "文件管理",
"icon": "",
"component": "fileManagement"
}
]
}
\ No newline at end of file
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "@rbc/file-management",
"version": "0.1.0",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build-dev": "vue-cli-service build --mode development",
"lint": "vue-cli-service lint"
},
"files": [
"dist",
"src",
"app.config.json"
],
"dependencies": {
"core-js": "^3.6.5",
"iviewex": "^2.6.26",
"js-base64": "^3.6.1",
"less-loader": "^5.0.0",
"nr.os.js": "^1.4.18",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuex": "^3.4.0",
"vxe-table": "^3.4.6",
"xe-utils": "^3.4.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"less": "^4.1.1",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.11"
}
}
<!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><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> 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>
/**
* 最后打包发布的时候会使用此文件,请将main.js中的引用部分转移到这里
* 不要写入公共依赖文件夹,不要引入iview,iviewex和vuex
*/
// import App from './App.vue'
// import {rserInit} from 'rser-basis-app' //默认执行一次basis的入口
import { fileManagement } from './views/index';
import Vue from 'vue'
import 'xe-utils'
import VXETable from 'vxe-table'
import 'vxe-table/lib/style.css'
Vue.use(VXETable)
// import vaCommon from '@va/common';
// import '@va/common/lib/css/main.css';
// // import 'rser-basis-app/src/public_library/ago.css';
// import ElementUI from 'element-ui';
// import 'element-ui/lib/theme-chalk/index.css';
// rserInit();
// Vue.use(vaCommon)
// Vue.use(ElementUI)
// Vue.prototype.$vaRewrite = {
// get: (url) => {
// let urlPre = ''
// if (window.osConfig.baseUrl) {
// urlPre = window.osConfig.baseUrl
// }
// if (url.indexOf('/api/') === 0) {
// urlPre = urlPre + url.substring(4)
// } else {
// urlPre = urlPre + url
// }
// return urlPre
// }
// }
// 在此处引入vuex和router,将下面导出对象改为{app: App, store: store, routes: router}
// import store from './Store'
// export default { app: App }
//安装mcon.js中的内容
window.$collector = window.GMS.getContext().getCollector();
window.GMS.getContext().getCollector().updateElements(require.context('./', true, /mcon\.js$/));
export default {
fileManagement: {
app: fileManagement
},
}
\ No newline at end of file
import Vue from 'vue'
import App from './App.vue'
import iview from 'iview'
import nros from 'nr.os.js'
import iviewex from 'iviewex'
import vuex from 'vuex'
// 公共资源目录,会引入nr.os提供的资源文件以供调试,打包时不会包含这些文件
import './public_library'
Vue.prototype.$utils = nros.SDK.utils
// 登录信息
const loginInfo = {
au_path: '/nvwa/login',
usr_name: 'admin',
usr_psw: 'admin',
tenant: '__default_tenant__'
}
const {
utils
} = nros.SDK
window.nros = nros
// const CRYPTO_KEY = lib.CryptoJS.enc.Utf8.parse('JIUQI/NEWREP/AES')
// const CRYPTO_VI = lib.CryptoJS.enc.Utf8.parse('JIUQI/NEWREP/AES')
// function encrypt (data) {
// return coding.enCoding(data,
// CRYPTO_KEY,
// { iv: CRYPTO_VI, mode: lib.CryptoJS.mode.CBC, padding: lib.CryptoJS.pad.ZeroPadding })
// }
// function decrypt (data) {
// return coding.deCoding(data,
// CRYPTO_KEY,
// { iv: CRYPTO_VI, mode: lib.CryptoJS.mode.CBC, padding: lib.CryptoJS.pad.ZeroPadding })
// }
const loginParam = {
username: loginInfo.usr_name,
pwd: loginInfo.usr_psw,
tenant: loginInfo.tenant,
encrypted: false
}
nros.restful.post(loginInfo.au_path, loginParam).then((res) => {
utils.setToken(res.token)
if (window._v) {
window._v.$Message.info(`${loginInfo.usr_name} 登录成功`)
} else {
console.log(`${loginInfo.usr_name} 登录成功`)
}
}).catch((res) => {
if (window._v) {
window._v.$Message.error(`<span>${loginInfo.usr_name} 登录失败</span><div style="margin-left: 15px;">info: ${res.data.message}</div>`)
} else {
console.log(`${loginInfo.usr_name} 登录失败`)
}
})
// 优先执行登录操作
setTimeout(() => {}, 1000)
// 保持原有app中调用名不变
Vue.prototype.$portalAPI = nros.event
Vue.use(nros.restful)
Vue.use(iview)
Vue.use(iviewex)
Vue.use(vuex)
// Vue.config.productionTip = false
window._v = new Vue({
render: h => h(App)
}).$mount('#app')
import fileManagement from './file-management.vue'
export {
fileManagement
}
\ No newline at end of file
const path = require('path')
var config = {
configureWebpack: {
watch: false ,
entry: {
app: './src/main.build.js'
},
devtool: 'source-map',
output: {
library: 'portal_application',
libraryTarget: 'window',
libraryExport: 'default',
filename: 'app.bundle.js'
// filename: '[name].js'
},
module: {
rules: [
{
test: /\.(mp4|flv|swf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",
options: {
name: 'video/[name].[hash:7].[ext]'
}
},
{
test: /\.(gif|jpg|png|woff|svg|eot|ttf)\?.*$/,
loader: 'url-loader?limit=8192'
}
]
},
externals: {
vue:'Vue',
jquery: 'jQuery',
['$']: 'jQuery',
'vue-router': 'VueRouter',
vuex: 'Vuex',
iview: 'iview',
iviewex: 'iviewex',
xlsx: 'XLSX'
},
resolve: {
alias: {
'@': path.resolve(__dirname,'src')
},
extensions: ['.js', '.vue']
}
},
chainWebpack: config => {
config.optimization.delete('splitChunks')
},
css: { extract: false }
}
lintOnSave: false,
module.exports = config
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
parserOptions: {
parser: 'babel-eslint'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-unused-vars': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/no-unused-components': 'off',
'vue/no-side-effects-in-computed-properties': 'off',
'vue/require-v-for-key': 'off',
'vue/no-unused-vars': 'off',
'no-prototype-builtins': 'off',
'no-extra-semi': 'off',
}
}
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
stages:
- install_deps
- lint
- build
cache:
paths:
- node_modules/
- dist/
# 安装依赖
install_deps:
stage: install_deps
only:
- master
script:
- npm install --registry http://10.2.38.78:4873/
tags:
- np-runner
# 统一代码格式
lint:
stage: lint
script:
- npm run lint
tags:
- np-runner
# 编译
build:
stage: build
only:
- master
script:
- npm run build
artifacts:
paths:
- dist
expire_in: 1 day
tags:
- np-runner
###app模板工程介绍
####目录结构
> demo
> ├─config `构建脚本`
> ├─public
> ├─src
> │ ├─assets
> │ ├─utils
> │ ├─views
> ├─.eslintrc.js
> ├─.gitignore
> ├─.gitlab-ci.yml
> ├─.npmignore
> ├─app.config.json `nr-os平台APP配置文件,收集APP所有信息`
> ├─babel.config.js
> ├─index.demo.js `nr.os下模块打包入口`
> ├─package.json
> ├─README.md
> └─vue.config.js
####创建APP工程
- dev.config.js 和 pro.config.js
```js
const path = require('path')
var config = {
configureWebpack: {
entry: {
app: './index.demo.js', //*****模块打包入口文件
},
devtool: 'source-map',
output: {
filename: '[name].bundle.js',
library: 'portal_application',
libraryTarget: 'umd',
libraryExport: 'default',
umdNamedDefine: true,
globalObject: 'this'
},
externals: {
'vue': {
root: 'Vue',
commonjs: 'vue',
commonjs2: 'vue',
amd: 'vue'
},
jquery: 'jQuery',
['$']: 'jQuery',
'vue-router': 'VueRouter',
vuex: 'Vuex',
iview: 'iview',
iviewex: 'iviewex'
},
module: {
rules: [
{
test: /\.(mp4|flv|swf)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",
options: {
name: 'video/[name].[hash:7].[ext]'
}
}
]
},
resolve: {
alias: { //*******全局定义的别名,只建议使用以下别名
'@common': path.resolve(__dirname,'../../common'),
'@components': path.resolve(__dirname,'../../components/src/views'),
'@api': path.resolve(__dirname,'../../common/api'),
'@utils': path.resolve(__dirname,'../../common/utils'),
'@gcRoot': path.resolve(__dirname,'../../'),
},
extensions: ['.js', '.vue']
},
},
css: { extract: false },
lintOnSave: false,
productionSourceMap: false,
}
module.exports = config
```
- app.config.json
```json5
{
"name": "@gc/demo",
"title": "测试App",
"author": "admin",
"keywords": "demo",
"company": "久其软件",
"type": false,
"version": "v0.1",
"license": "",
"description": "",
"icon":"icon-_ZSYshujuluru",
"data": {
"static": [ //**********app个性静态文件
{"name": "vuex", "url": "static/lib/vuex.min.js"}
],
"app": {
"component": ["dist/app.bundle.js"] //**********不要修改
},
"config": [ //**********app入口参数
{
"title":"模版",
"key":"code",
"type": "array",
"dataSource": {
"api":"/api/define",
"titleColumn":"title",
"valueColumn": "code"
}
}
]
}
}
```
####**注意事项**
- 模块命名规范
- 模块互相引用,本模块的依赖应该包含被包含模块的依赖
- 定义了一些全局别名,每个模块强制使用。模块自己的别名建议不要设置,除非确定别人不会通过路径引用你的模块。
- 模块间的代码依赖方式,路径引用到组件的 index.js
{
"name": "invoice",
"title": "智慧票据",
"author": "admin",
"keywords": "invoice",
"company": "久其软件",
"type": false,
"version": "v0.1",
"license": "",
"description": "",
"icon":"icon-_ZSYshujuluru",
"expose": [
{
"title": "智慧票据",
"icon": "",
"component": "InvoiceList"
}
],
"data": {
"static": [
{"name": "vuex", "url": "static/lib/vuex.min.js"}
],
"app": {
"component": ["dist/app.bundle.js"]
},
"config": [
]
}
}
module.exports = {
presets: [
// '@vue/cli-plugin-babel/preset',
['@vue/app', { useBuiltIns: "entry" }],
// [
// "@babel/preset-env",
// {
// useBuiltIns: "usage"
// }
// ]
],
}
/**
* 最后打包发布的时候会使用此文件,请将main.js中的引用部分转移到这里
* 不要写入公共依赖文件夹,不要引入iview,iviewex和vuex
*/
import Vue from 'vue'
import InvoiceList from './src/views/invoice-list'
// 在此处引入vuex和router,将下面导出对象改为{app: App, store: store, router: router}
// import store from './Store'
export default {
InvoiceList: {
app: InvoiceList,
},
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "@rbc/invoice",
"version": "1.1.0--SNAPSHOT",
"main": "dist/app.bundle.js",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build-dev": "vue-cli-service build --mode development",
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^0.19.2",
"core-js": "^2.6.12",
"element-resize-detector": "^1.1.15",
"iviewex": "^2.6.26",
"js-base64": "^3.4.5",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"moment": "^2.29.1",
"nr.os.js": "^1.4.7",
"number-precision": "^1.2.0",
"pdfjs-dist": "^2.10.377",
"view-design": "^4.3.2",
"viewerjs": "^1.10.2",
"vue": "^2.6.11",
"vue-router": "^3.0.3",
"vuex": "^3.0.1"
},
"files": [
"dist",
"src",
"app.config.json"
],
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"less": "^4.1.1",
"less-loader": "^7.3.0",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2",
"svg-sprite-loader": "^6.0.11",
"vue-template-compiler": "^2.6.11"
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}
<!DOCTYPE html>
<html lang="en">
<script>
window.netConfig = {
completeUrl: '',
thinMode: false,
cookieExpires: 1,
}
</script>
<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>hello-world</title>
</head>
<body>
<noscript>
<strong>We're sorry but hello-world 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>
<Button :disabled="!selectedRows.length" size="small" type="text" @click="handleClick">删除</Button>
</template>
<script>
export default {
props: {
selectedRows: {
type: Array,
default: () => [],
},
},
methods: {
handleClick() {
this.$Modal.confirm({
title: '确认删除?',
content: `<p>确定要删除${this.selectedRows.length}项数据吗?</p>`,
onOk: () => {
window.GMS.$http.post(
`/yxgl/deleteImage`,
[...this.selectedRows],
).then((res) => {
if (res.data && res.data.code != 0) {
this.$Message.error(res.data.msg)
}
}).catch(() => {
this.$Message.warning('删除失败');
}).finally(() => {
this.$emit('after-click')
})
},
onCancel: () => {
},
})
},
},
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<div>
<Button
:disabled="!selectedRows.length || selectedRows.length > 1"
size="small"
type="text"
@click="modalVisible = true"
>修改图像描述</Button>
<Modal
v-model="modalVisible"
title="修改图像描述"
@on-ok="handleOk"
@on-cancel="handleCancel"
>
<Form :label-width="80">
<FormItem label="原描述">
<Input :value="selectedRows[0] && selectedRows[0].imageDesc" disabled />
</FormItem>
<FormItem label="新描述">
<Input v-model="newDescription" />
</FormItem>
</Form>
</Modal>
</div>
</template>
<script>
export default {
props: {
selectedRows: {
type: Array,
default: () => [],
},
},
data() {
return {
modalVisible: false,
newDescription: '',
}
},
methods: {
handleOk() {
window.GMS.$http.post(
`/yxgl/updateImageDesc`,
{ ...this.selectedRows[0], imageDesc: this.newDescription }
).catch(() => {
this.$Message.warning('修改失败');
}).finally(() => {
this.newDescription = ''
this.$emit('after-click')
})
},
handleCancel() {
this.modalVisible = false
}
},
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<Button
:disabled="!selectedRows.length || selectedRows.length > 1 || selectedRows[0].taskType == 1"
size="small"
type="text"
@click="handleClick"
>
识别
</Button>
</template>
<script>
export default {
props: {
selectedRows: {
type: Array,
default: () => [],
},
},
watch: {
selectedRows(val) {
console.log(val)
}
},
methods: {
handleClick() {
window.GMS.$http.post(
`/yxgl/ocr`,
{ ...this.selectedRows[0] }
).then((res) => {
if (res.data && res.data.code != 0) {
this.$Message.error(res.data.msg)
}
}).finally(() => {
this.$emit('after-click')
})
},
},
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<div>
<Button
:disabled="!selectedRows.length"
size="small"
type="text"
@click="modalVisible = true"
>票据转发</Button>
<Modal
v-model="modalVisible"
title="票据转发"
@on-ok="handleOk"
@on-cancel="handleCancel"
>
<Form>
<FormItem label="接收人" :label-width="80">
<gms-basedata-tree
title="选择接收人"
tableName="MD_STAFF"
node-key="id"
v-model="basedata"
:multiple="false"
:onlyChooseLeaf="false"
:clearable="true"
:searchable="true"
/>
</FormItem>
</Form>
</Modal>
</div>
</template>
<script>
export default {
props: {
selectedRows: {
type: Array,
default: () => [],
},
},
data() {
return {
modalVisible: false,
basedata: null,
}
},
methods: {
handleOk() {
if (!this.basedata || !this.basedata.objectcode) {
this.$Message.warning('请选择接收人');
return
}
window.GMS.$http.post(
`/yxgl/transferUser`,
this.selectedRows.map((o) => ({
...o,
userId: this.basedata.objectcode,
userName: this.basedata.name,
}))
).catch(() => {
this.$Message.warning('修改失败');
}).finally(() => {
this.basedata = null
this.$emit('after-click')
})
},
handleCancel() {
this.modalVisible = false
},
},
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<div>
<Button size="small" type="text" @click="modalVisible = true">
票据转发记录
</Button>
<Modal
v-model="modalVisible"
title="票据转发记录"
@on-ok="handleOk"
@on-cancel="handleCancel"
width="70%"
>
<Form>
<FormItem label="起止时间" :label-width="80">
<DatePicker
:value="dateRange"
type="daterange"
style="width: 300px"
@on-change="handleDateChange"
></DatePicker>
</FormItem>
</Form>
<Table :loading="loading" border :columns="columns1" :data="tableData"></Table>
<Page
:total="total"
show-sizer
:current="pagination.pageSize"
:page-size="pagination.pageCount"
@on-change="pagination.pageSize = $event"
@on-page-size-change="pagination.pageCount = $event"
/>
</Modal>
</div>
</template>
<script>
import moment from "moment";
export default {
props: {},
data() {
return {
dateRange: [
moment().subtract(10, "days").format("YYYY-MM-DD"),
moment().format("YYYY-MM-DD"),
],
modalVisible: false,
columns1: [
{
title: "图像描述",
key: "imageDesc",
},
{
title: "原用户",
key: "oldUser",
width: 120,
},
{
title: "新用户",
key: "newUser",
width: 120,
},
{
title: "部门",
key: "deptName",
width: 200,
},
{
title: "时间",
key: "formatTime",
width: 200,
},
],
tableData: [],
total: 0,
loading: false,
pagination: {
pageSize: 1,
pageCount: 10,
},
}
},
watch: {
modalVisible(val) {
if (val) {
this.pagination = {
pageSize: 1,
pageCount: 10,
}
}
},
pagination: {
deep: true,
handler() {
this.queryInfo()
},
},
},
methods: {
queryInfo() {
this.loading = true
this.tableData = []
this.total = 0
let dateParam = {}
if (this.dateRange && this.dateRange[0]) {
dateParam = {
beginDate: moment(this.dateRange[0]).format("YYYYMMDD"),
endDate: moment(this.dateRange[1]).format("YYYYMMDD"),
}
}
window.GMS.$http
.post(`/yxgl/selectTransferUser`, {
...dateParam,
...this.pagination,
})
.then((result) => {
const rows = result?.data?.rows || [];
const promiseList = rows.map((row) => {
return window.GMS.$http.post(`/baseData/data/list`, {
objectcode: row.deptId,
tableName: 'MD_DEPARTMENT',
pagination: false,
searchKey: "",
queryChildrenType: 'ALL_CHILDREN_WITH_SELF',
queryDataStructure: 'ALL_WITH_REF',
stopflag: -1,
authType: 'NONE',
}).then((res) => {
return res?.data?.rows?.[0]?.name
})
})
Promise.all(promiseList).then(res => {
for (let i = 0; i < res.length; ++i) {
rows[i].deptName = res[i]
rows[i].formatTime = moment(rows[i].createTime).format('YYYY-MM-DD HH:mm:ss')
}
this.tableData = rows
this.total = result?.data?.total || 0
this.loading = false
})
})
.catch(() => {
this.loading = false
this.$Message.warning("查询失败")
})
},
handleDateChange(val) {
this.dateRange = val
this.queryInfo()
},
handleOk() {
return
},
handleCancel() {
this.modalVisible = false
},
},
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<el-upload
class="upload-demo"
:on-change="handleFileChange"
:http-request="handleClick"
:show-file-list="false"
>
<Button size="small" type="text" @click="handleClick">票据导入</Button>
</el-upload>
</template>
<script>
import moment from 'moment'
export default {
props: {
selectedRows: {
type: Array,
default: () => [],
},
},
data() {
return {
file: null,
}
},
computed: {
baseUrl() {
return'http://10.2.9.28:8091'
}
},
methods: {
handleFileChange(file) {
this.file = file
},
handleClick() {
if (!this.file) return
const param = new FormData()
param.append('file', this.file.raw)
param.append('ownerId', '0232228d-b2d2-4911-ace6-6a191b594439')
param.append('ownerType', 'eis')
param.append('category', `eis\\${moment().format('YYYYMMDD')}\\`)
window.GMS.$http.post(
`/yxgl/upload`,
param,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then((res) => {
if (res.data && res.data.code != 0) {
this.$Message.error(res.data.msg)
}
}).finally(() => {
this.file = null
this.$emit('after-click')
})
return false
},
},
}
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="invoice-image-info">
<div class="title-wrapper">
<ImageTab :options="tabList" v-model="tabKey" />
<div class="button-wrapper">
<Button :disabled="isInfoEdit || imageInfo.checkFlag == 2" size="small" @click="isInfoEdit = true">修改</Button>
<Button :disabled="!isInfoEdit" size="small" @click="handleSave">保存</Button>
<Button
v-if="!hideVerification(imageInfo)"
:disabled="isInfoEdit || imageInfo.checkFlag == 2"
size="small"
@click="handleVerification"
>
查验
</Button>
</div>
</div>
<ImageInfoPanel :loading="loading" :imageInfo="imageInfo" :isInfoEdit="isInfoEdit" />
</div>
</template>
<script>
import ImageTab from './image-tab.vue'
import ImageInfoPanel from './image-info-panel.vue'
import { verificationTypeList } from '../utils'
export default {
components: {
ImageTab,
ImageInfoPanel,
},
props: {
currentSelectedRow: {
type: Object,
default: () => ({}),
}
},
data() {
return {
isInfoEdit: false,
imageInfoList: [],
imageInfo: {},
tabKey: 0,
tabList: [],
loading: false,
}
},
computed: {
},
watch: {
tabKey(val) {
this.imageInfo = { ...this.imageInfoList[val] }
},
},
created() {
this.queryImageInfo()
},
methods: {
hideVerification(imageInfo) {
if (verificationTypeList.includes(imageInfo.billType)) {
return false
}
return true
},
handleVerification() {
this.loading = true
window.GMS.$http.post(
`/yxgl/verification`,
{ ...this.imageInfo }
).then((res) => {
if (res.data && res.data.code != 0) {
this.$Message.error(res.data.msg)
}
}).finally(() => {
this.queryImageInfo()
})
},
handleSave() {
this.isInfoEdit = false
window.GMS.$http.post(
`/yxgl/saveDetails`,
{ ...this.imageInfo }
).finally(() => {
this.queryImageInfo()
})
},
queryImageInfo() {
this.loading = true
window.GMS.$http.post(
`/yxgl/selectDetails`,
{ ...this.currentSelectedRow }
).then((res) => {
this.loading = false
this.imageInfoList = res?.data?.rows || []
this.tabList = this.imageInfoList.map((o, index) => ({
label: `发票${index + 1}`,
value: index,
}))
this.tabKey = 0
this.imageInfo = { ...(res?.data?.rows?.[this.tabKey] || {}) }
this.$emit('load-info', this.imageInfoList)
})
},
},
};
</script>
<style lang="less">
.invoice-image-info {
padding: 16px 16px 0px 16px;
.title-wrapper {
position: relative;
height: 46px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #e8e8e8;
margin-bottom: 16px;
&::before {
position: absolute;
left: 0;
top: 15px;
content: "";
width: 3px;
height: 16px;
background: #4bc0c6;
}
.title {
margin-left: 12px;
height: 22px;
font-size: 16px;
font-weight: 500;
color: #555555;
line-height: 22px;
}
.button-wrapper {
button {
&:not(:last-child) {
margin-right: 10px;
}
}
}
}
}
</style>
\ No newline at end of file
<template>
<div class="tab-row">
<div
v-for="option in options"
:key="option.value"
:class="`tab-button${option.value == value ? ' tab-button-active' : ''}`"
@click="$emit('input', option.value)"
>
<div class="title">{{option.label}}</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
}
},
props: {
options: {
type: Array,
default: () => [],
},
value: {
default: '',
},
},
}
</script>
<style lang="less" scoped>
.tab-row {
display: flex;
background-color: #F8F8F8;
.tab-button {
cursor: pointer;
padding: 0 16px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
.title {
height: 20px;
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
}
.tab-button-active {
background-color: white;
.title {
height: 20px;
font-size: 14px;
font-weight: 400;
line-height: 20px;
font-weight: 500;
color: #03A4AD;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="invoice-image-table-wrapper">
<ImageTab v-if="mode === 0" :options="tabList" :value="currentTab" @input="currentTab = $event" />
<div class="table-row">
<div class="table-wrapper">
<Table
@on-selection-change="handleSelectionChange"
size="medium"
border
ref="selection"
:columns="tableColumns"
:data="tableData"
height="409"
:loading="loading"
>
<template slot-scope="{ row }" slot="sourceType">
{{row.sourceType == 1 ? '移动端' : 'PC端'}}
</template>
<template slot-scope="{ row }" slot="taskType">
{{row.taskType == 0 ? '识别失败' : row.taskType == 1 ? '识别成功' : '未识别'}}
</template>
</Table>
<div class="pagination">
<div class="pagination-info">
已选{{currentSelection.length}}条,已选金额{{totalMoney}}元
</div>
<Page
:total="total"
:current="pagination.pageSize"
:page-size="pagination.pageCount"
@on-change="pageSizeChange"
@on-page-size-change="pageCountChange"
size="small"
show-total
show-elevator
show-sizer
/>
</div>
</div>
<div v-show="currentSelection.length === 1" class="image-wrapper">
<Spin v-if="!currentImgUrl" fix></Spin>
<img @dblclick="viewImage" :src="currentImgUrl" alt="">
</div>
</div>
<ImageInfo
v-if="currentSelection.length === 1"
:currentSelectedRow="currentSelection[0]"
@load-info="handleLoadDetailInfo"
/>
</div>
</template>
<script>
import ImageTab from './image-tab.vue'
import ImageInfo from './image-info.vue'
import { getImgUrl, verificationTypeList } from '../utils'
// eslint-disable-next-line
import ImageViewModal from './image-view-modal/image-view-modal.vue'
export default {
components: {
ImageTab,
ImageInfo,
},
props: ['searchParams', 'mode'],
data() {
const defaultPagination = {
pageSize: 1,
pageCount: 10,
}
return {
totalMoneyMap: new Map(),
totalMoney: 0,
currentTab: 0,
tabList: [
{
label: '未引用',
value: 0,
},
{
label: '已引用',
value: 1,
},
{
label: '全部',
value: 2,
},
],
currentSelection: [],
tableColumns: [
{
type: 'selection',
width: 60,
align: 'center'
},
{
title: '图像描述',
key: 'imageDesc'
},
{
title: '影像来源',
width: 100,
slot: 'sourceType',
},
{
title: '识别状态',
width: 100,
slot: 'taskType',
},
{
title: '异常原因',
key: 'errorMessage',
},
{
title: '文件名称',
key: 'imageFileName',
},
{
title: '上传时间',
key: 'createTime',
}
],
tableData: [
],
tableDataMap: new Map(),
defaultPagination,
pagination: {
...defaultPagination,
},
loading: false,
currentImgUrl: null,
}
},
watch: {
currentSelection(val) {
this.getTotalMoney(val)
if (this.currentImgUrl) {
window.URL.revokeObjectURL(this.currentImgUrl)
}
this.currentImgUrl = null
if (val.length == 1) {
getImgUrl(val[0].id, val[0].yearFlag).then((res) => {
this.currentImgUrl = res.url
})
}
},
currentTab() {
this.pagination = {
...this.defaultPagination,
}
this.queryData()
}
},
mounted() {
this.queryData()
},
unmounted() {
if (this.currentImgUrl) {
window.URL.revokeObjectURL(this.currentImgUrl)
}
},
methods: {
viewImage() {
const imageId = this.currentSelection[0].id
const yearFlag = this.currentSelection[0].yearFlag
window.GMS.$hideContainer.addComponent(ImageViewModal, {}, function (c) {
c.yearFlag = yearFlag
c.imageId = imageId
})
},
pageSizeChange(val) {
this.pagination.pageSize = val
this.queryData()
},
pageCountChange(val) {
this.pagination.pageCount = val
this.queryData()
},
getTotalMoney(selection) {
this.totalMoney = selection.reduce((total, current) => {
return total + this.totalMoneyMap.get(current.id)
}, 0)
this.totalMoney = this.totalMoney.toFixed(2)
if (isNaN(this.totalMoney)) this.totalMoney = 0
},
handleLoadDetailInfo(detailInfoList) {
if (!detailInfoList.length) return
this.setTotalMoneyByDetailInfoList(detailInfoList)
this.setVerification(detailInfoList)
this.getTotalMoney(this.currentSelection)
},
handleSelectionChange(selection) {
this.currentSelection = selection
this.$emit('selectionChange', selection)
},
clearSelection() {
this.currentSelection = []
this.$emit('selectionChange', [])
},
setVerification(detailInfoList) {
let flag = true
for (let data of detailInfoList) {
if (verificationTypeList.includes(data.billType)) {
if (data.checkFlag != 2) {
flag = false
break
}
}
}
if (flag) {
this.tableDataMap.get(detailInfoList[0].imageId).frontendVerificationStatus = true
}
else {
this.tableDataMap.get(detailInfoList[0].imageId).frontendVerificationStatus = false
}
},
setTotalMoneyByDetailInfoList(detailInfoList) {
let totalMoney = 0
for (let info of detailInfoList) {
if (info.billtypeDetailId == '999') continue
totalMoney += info.totalMoney
}
this.totalMoneyMap.set(detailInfoList[0].imageId, totalMoney)
},
queryData({ params: p = this.searchParams, pagination = this.pagination } = {}) {
this.pagination = pagination
const params = {
...p,
...this.pagination,
reffstate: this.currentTab,
}
this.clearSelection()
this.loading = true
window.GMS.$http.post(
`/yxgl/selectAll`,
params,
).then((res) => {
this.tableDataMap = new Map()
this.tableData = res?.data?.rows || []
this.tableData.forEach((row) => {
this.tableDataMap.set(row.id, row)
})
this.total = res?.data?.total || 0
this.totalMoneyMap = new Map()
const promiseList = this.tableData.map((row) => {
return window.GMS.$http.post(
`/yxgl/selectDetails`,
{ ...row }
).then((res) => {
return res?.data?.rows || []
})
})
Promise.all(promiseList).then((res) => {
res.forEach((detailInfoList) => {
if (!detailInfoList.length) return
this.setTotalMoneyByDetailInfoList(detailInfoList)
this.setVerification(detailInfoList)
})
this.loading = false
})
})
},
},
}
</script>
<style lang="less">
.invoice-image-table-wrapper {
background-color: white;
.ivu-table-row {
height: 36px;
}
.table-row {
display: flex;
padding: 16px;
.table-wrapper {
width: ~"calc(100% - 359px)";
.pagination {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: space-between;
.pagination-info {
height: 17px;
font-size: 12px;
font-weight: 400;
color: #555555;
line-height: 17px;
}
}
}
.image-wrapper {
position: relative;
margin-left: 16px;
padding: 12px 10px;
width: 359px;
height: 409px;
background: #FFFFFF;
border: 1px solid #DDDDDD;
img {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
}
}
}
}
</style>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
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