blob: f0eebb321c4e583d24ceda7fdb8c2d98ebca3fb6 [file] [log] [blame]
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<template>
<div class="function-management">
<Form class="function-management-searchbar" @submit.native.prevent :model="searchBar" inline>
<FormItem prop="functionName" :label="$t('message.linkis.udf.functionName')">
<Input
v-model="searchBar.functionName"
:placeholder="$t('message.linkis.udf.functionName')"
style="width:120px;"
></Input>
</FormItem>
<Divider type="vertical" class="divider" />
<FormItem prop="functionType" :label="$t('message.linkis.udf.functionType')">
<Select v-model="searchBar.functionType" style="width:120px;">
<Option :label="$t('message.linkis.all')" value="3,4" key="3,4" />
<Option label="python" value="3" key="3" />
<Option label="scala" value="4" key="4" />
</Select>
</FormItem>
<Divider type="vertical" class="divider" />
<!-- <FormItem prop="creator" :label="$t('message.linkis.udf.creator')">
<Select v-model="searchBar.creator" style="width:120px;">
<Option
v-for="(item) in getCreators"
:label="item === 'all' ? '全部': item"
:value="item.value"
:key="item.value"
/>
</Select>
</FormItem> -->
<!-- <Divider type="vertical" class="divider" /> -->
<FormItem>
<Button
type="primary"
@click="search()"
style="margin-right: 10px;"
>{{ $t('message.linkis.udf.search') }}</Button>
<Button
type="success"
@click="showAddModal(true)"
style="margin-right: 10px;"
>{{ $t('message.linkis.udf.addFunction') }}</Button>
</FormItem>
</Form>
<div>
<div class="function-management-table" :style="{'height': moduleHeight+'px'}">
<Icon v-show="isLoading" type="ios-loading" size="30" class="function-management-loading" />
<history-table
v-if="!isLoading"
:columns="column"
:data="list"
:height="moduleHeight"
:no-data-text="$t('message.linkis.noDataText')"
border
stripe
@checkall="checkChange"
@select-change="selectChange"
/>
</div>
<div class="function-management-page">
<Page
:total="pageSetting.total"
:page-size="pageSetting.pageSize"
:current="pageSetting.current"
size="small"
show-total
show-elevator
@on-change="changePage"
:prev-text="$t('message.linkis.previousPage')" :next-text="$t('message.linkis.nextPage')"
/>
</div>
</div>
<!-- 新增函数 -->
<add-function-modal
ref="fn"
:loading="loading"
:tree="shareTree"
:load-data-fn="loadShareTreeFn"
:filter-node="filterNode"
:is-udf="false"
@add="addFunction"
@update="updateFunction"
/>
<!-- 移交 -->
<Modal
:title="$t('message.linkis.udf.changeuser')"
v-model="changUserModal"
:mask-closable="false"
@on-visible-change="changUserModalChange"
>
<span>{{$t('message.linkis.udf.changeUserTo')}}</span>
<Select ref="userSelect" v-model="handleUser" filterable
v-if="allUsers.length"
:remoteMethod="filterSelect"
@on-query-change="queryChange"
:placeholder="$t('message.linkis.udf.inputUser')" style="width:200px;">
<Option
v-for="(item) in udfUsers"
:label="item"
:value="item"
:key="item"
/>
</Select>
<Input v-if="!allUsers.length" v-model="handleUser" :placeholder="$t('message.linkis.udf.inputUser')" style="width: 250px" />
<div slot="footer">
<Button @click="changUserModal=false">{{$t('message.linkis.udf.cancel')}}</Button>
<Button type="primary" :disabled="!this.handleUser" @click="changeUser">{{$t('message.linkis.udf.confirm')}}</Button>
</div>
</Modal>
<Modal
:title="$t('message.linkis.udf.share')"
v-model="shareModal"
:mask-closable="false"
@on-ok="share"
>
<span>{{$t('message.linkis.udf.shareUser')}}</span>
<Input
v-model="sharedUsers"
type="textarea"
:autosize="{ minRows: 2, maxRows: 5 }"
:placeholder="$t('message.linkis.udf.separateWithCommas')"
/>
</Modal>
<Modal
:title="$t('message.linkis.udf.versionList')"
v-model="vlistModal"
width="1024"
:mask-closable="false"
@on-visible-change="vModalChange"
>
<vlist :row="handleRow" @refresh-list="search"/>
</Modal>
</div>
</template>
<script>
import moment from 'moment';
import storage from '@/common/helper/storage'
import table from '@/components/virtualTable'
import mixin from '@/common/service/mixin'
import api from '@/common/service/api'
import addFunctionModal from './addFunctionModal'
import vlist from './vlist'
export default {
name: 'FunctionManagement',
components: {
historyTable: table.historyTable,
addFunctionModal,
vlist
},
mixins: [mixin],
data() {
return {
list: [],
column: [],
getFunctionTypes: [],
getCreators: [],
isLoading: false,
pageSetting: {
total: 0,
pageSize: 25,
current: 1
},
searchBar: {
functionName: '',
functionType: '3,4',
creator: '',
},
inputType: 'number',
moduleHeight: 300,
addFunctionModal: {
functionName: '',
functionType: '',
availableCluster: ''
},
changUserModal: false,
handleUser: '',
loading: false,
shareTree: [],
shareModal: false,
vlistModal: false,
sharedUsers: '',
handleRow: {},
udfUsers: [],
allUsers: []
}
},
created() {
// 获取函数类型
// api.fetch('/configuration/engineType', 'get').then(res => {
// window.console.log('res.engineType: ', res.engineType);
// this.getFunctionTypes = ['all', ...res.engineType]
// })
// this.getFunctionTypes = ['all', '0', '1,2']
// 获取创建者
// api.fetch('/configuration/engineType', 'get').then(res => {
// this.getCreators = ['all', ...res.engineType]
// })
// 所有用户列表,移交时选择用户
},
mounted() {
this.init()
this.moduleHeight = this.$parent.$el.clientHeight - 228
// 监听窗口变化,获取浏览器宽高
window.addEventListener('resize', this.getHeight)
this.getRootPath(() => {
this.getTree((tree) => {
if (tree) {
this.shareTree.push(tree);
}
});
});
},
beforeDestroy() {
// 监听窗口变化,获取浏览器宽高
storage.set('last-fnsearchbar-status', this.searchBar)
window.removeEventListener('resize', this.getHeight)
},
activated() {
this.init()
},
methods: {
getRootPath(cb) {
this.rootPath = storage.get('shareRootPath', 'session');
if (!this.rootPath) {
api.fetch(`/filesystem/getUserRootPath`, {
pathType: 'file',
}, 'get').then((rst) => {
if (rst.userLocalRootPath) {
storage.set('shareRootPath', rst.userLocalRootPath, 'session');
this.rootPath = rst.userLocalRootPath;
cb(true);
} else {
this.$Message.warning(this.$t('message.scripts.warning.getRootPath'));
cb(false);
}
}).catch(() => {
cb(false);
});
} else {
cb(true);
}
},
getTree(cb) {
const timeout = setTimeout(() => {
this.compLoading = true;
}, 2000);
api.fetch(`/filesystem/getDirFileTrees`, {
path: this.rootPath,
}, 'get')
.then((rst) => {
clearTimeout(timeout);
this.compLoading = false;
if (rst) {
const tree = rst.dirFileTrees;
cb(tree);
// 树结构存储到indexedDB
}
this.timeoutFlag = true;
}).catch(() => {
this.compLoading = false;
cb(false);
});
},
loadShareTreeFn(node, cb) {
this.treeLoading = true;
const timeout = setTimeout(() => {
this.compLoading = true;
}, 2000);
api.fetch(
`/filesystem/getDirFileTrees`, {
path: node.data.path,
},
'get'
).then((rst) => {
clearTimeout(timeout);
this.compLoading = false;
this.treeLoading = false;
const tree = rst.dirFileTrees.children;
cb(tree);
// this.$nextTick(() => {
// seesion存储改为indexDB存储过程中,将存储的数据结构改变,以前是纯数组,现在是对象里的value值判断,所以得改项目里其他用到缓存地方的判断
// fileTree没有变动,应该不用更新到indexDB,由于树组件打开子节点会清空
// this.dispatch('IndexedDB:appendTree', { treeId: 'scriptTree', value: this.fileTree });
// });
}).catch(() => {
clearTimeout(timeout);
this.compLoading = false;
this.treeLoading = false;
})
},
getHeight() {
this.moduleHeight = this.$parent.$el.clientHeight - 228
},
init() {
const lastSearch = storage.get('last-fnsearchbar-status')
if (lastSearch && lastSearch.shortcut) {
if (lastSearch.shortcut[0] && lastSearch.shortcut[1]) {
lastSearch.shortcut = [new Date(lastSearch.shortcut[0]), new Date(lastSearch.shortcut[1])]
} else {
const today = new Date(new Date().toLocaleDateString())
lastSearch.shortcut = [today, today]
}
this.searchBar = lastSearch
}
this.search()
},
getParams() {
const params = {
udfName: this.searchBar.functionName,
udfType: this.searchBar.functionType,
createUser: this.searchBar.creator,
curPage: this.pageSetting.current,
pageSize: this.pageSetting.pageSize,
}
return params
},
changePage(page) {
this.pageSetting.current = page
this.search(page)
},
search(page) {
this.pageSetting.current = page || 1
this.isLoading = true
const params = this.getParams()
this.column = this.getColumns()
api
.fetch('/udf/managerPages', params, 'post')
.then(rst => {
this.pageSetting.total = rst.total
this.isLoading = false
this.list = (rst.infoList || []).map(it=>{
it.udfTypeText = it.udfType === 3 ? 'python' : 'scala'
it.status = it.expire ? this.$t('message.linkis.udf.expire') : this.$t('message.linkis.udf.normal')
it.createTimeFormat = moment(it.createTime).format('YYYY-MM-DD HH:mm:ss')
return it
})
})
.catch(() => {
this.list = [{}]
this.isLoading = false
})
},
showAddModal(show, data) {
if(show) {
this.$refs.fn.open(data)
} else {
this.$refs.fn.close()
}
},
// 新增函数
addFunction(data) {
if (this.loading) return
this.loading = true
const params = {
udfName: data.name,
udfType: data.udfType,
description: data.description,
path: data.path,
// shared: true,
useFormat: data.useFormat,
// expire: true,
load: data.defaultLoad,
registerFormat: data.registerFormat,
sys: 'IDE',
clusterName: data.clusterName,
directory: data.directory
}
api
.fetch('/udf/add', {udfAddVo: params}, 'post')
.then(() => {
this.showAddModal(false)
this.search()
this.isLoading = false
this.loading = false
if (data.defaultLoad) {
this.confirmKillIdle()
}
})
.catch(() => {
// this.list = [{}]
this.isLoading = false
this.loading = false
})
},
// 更新
updateFunction(data) {
if (this.loading) return
this.loading = true
const params = {
udfUpdateVo: {
id: this.handleRow.id,
udfName: data.name,
udfType: data.udfType,
description: data.description,
path: data.path,
useFormat: data.useFormat,
registerFormat: data.registerFormat,
// sys: 'all',
// clusterName: data.clusterName,
// directory: data.directory
}
}
api
.fetch('/udf/update', params, 'post')
.then(() => {
this.showAddModal(false)
this.isLoading = false
this.loading = false
this.search()
this.$Message.success(this.$t('message.linkis.udf.success'));
if (data.defaultLoad) {
this.confirmKillIdle()
}
})
.catch(() => {
this.isLoading = false
this.loading = false
})
},
checkChange(v) {
this.list = this.list.map(it => {
it.checked = !it.disabled && v
return it
})
},
selectChange() {
this.list = this.list.slice(0)
},
getColumns() {
const column = [
{
title: this.$t('message.linkis.udf.functionName'),
key: 'udfName',
align: 'center',
width: 150,
},
{
title: this.$t('message.linkis.udf.functionType'),
key: 'udfTypeText',
align: 'center',
width: 90
},
{
title: this.$t('message.linkis.udf.status'),
key: 'status',
align: 'center',
width: 80,
},
{
title: this.$t('message.linkis.udf.availableCluster'),
key: 'clusterName',
align: 'center',
width: 120,
},
{
title: this.$t('message.linkis.udf.class'),
key: 'directory',
align: 'center',
width: 100,
},
{
title: this.$t('message.linkis.udf.functionDescription'),
key: 'description',
align: 'center',
width: 150,
// 溢出以...显示
ellipsis: true
},
{
title: this.$t('message.linkis.udf.lastModifyTime'),
key: 'createTimeFormat',
align: 'center',
width: 180,
},
{
title: this.$t('message.linkis.udf.creator'),
key: 'createUser',
align: 'center',
width: 120,
},
{
title: this.$t('message.linkis.udf.action.title'),
key: 'action',
align: 'center',
width: 360,
renderType: 'button',
renderParams: [
{
label: this.$t('message.linkis.udf.action.edit'),
action: this.edit,
match: (v, row)=>{ return row.operationStatus.canUpdate},
style: {
backgroundColor: '#2d8cf0',
color: '#fff',
padding: '1px 7px 2px 7px !important',
marginRight: '5px'
}
},
{
label: this.$t('message.linkis.udf.action.vlist'),
action: this.vlist,
style: {
backgroundColor: '#2d8cf0',
color: '#fff',
padding: '1px 7px 2px 7px !important',
marginRight: '5px'
}
},
{
label: this.$t('message.linkis.udf.action.share'),
action: this.share,
match: (v, row)=>{ return row.operationStatus.canShare},
style: {
backgroundColor: '#2d8cf0',
color: '#fff',
padding: '1px 7px 2px 7px !important',
marginRight: '5px'
}
},
{
label: this.$t('message.linkis.udf.action.changeuser'),
action: this.changeUser,
match: (v, row)=>{ return row.operationStatus.canHandover},
style: {
backgroundColor: '#2d8cf0',
color: '#fff',
padding: '1px 7px 2px 7px !important',
marginRight: '5px'
}
},
{
label: this.$t('message.linkis.udf.action.delete'),
action: this.delete,
match: (v, row)=>{ return row.operationStatus.canDelete},
style: {
backgroundColor: '#ed4014',
color: '#fff',
padding: '1px 7px 2px 7px !important',
marginRight: '5px'
}
},
{
label: this.$t('message.linkis.udf.action.expire'),
action: this.expire,
match: (v, row)=>{ return row.operationStatus.canExpire},
style: {
backgroundColor: '#ff9900',
color: '#fff',
padding: '1px 7px 2px 7px !important'
}
},
]
},
]
return column
},
edit(args) {
this.handleRow = args.row
this.showAddModal(true, args.row)
},
delete(args) {
if (!args.row) return
this.$Modal.confirm({
title: this.$t('message.linkis.modal.modalTitle'),
content: this.$t('message.linkis.modal.modalDelete', {name: args.row.udfName}),
onOk: ()=>{
api
.fetch(`/udf/delete/${args.row.id}`, {}, 'post')
.then(() => {
this.search()
this.$Message.success(this.$t('message.linkis.udf.success'));
})
.catch(() => {
})
}
})
},
vlist(args) {
this.handleRow = args.row
this.vlistModal = true
},
share(args) {
if (!this.shareModal && args) {
this.sharedUsers = ''
this.shareModal = true
this.handleRow = args.row
this.getShareUsers().then(res=> {
this.sharedUsers = Array.isArray(res.sharedUsers) ? res.sharedUsers.join(',') : ''
})
} else {
const params = {
udfInfo: {
id: this.handleRow.id,
udfName: this.handleRow.name,
udfType: this.handleRow.type
},
sharedUsers: this.sharedUsers.split(',').map(it=>it.trim()).filter(it=>!!it)
}
this.shareModal = false
api
.fetch('/udf/shareUDF', params, 'post')
.then(() => {
this.$Message.success(this.$t('message.linkis.editedSuccess'))
this.search()
})
.catch(() => {
})
}
},
expire(args) {
this.handleRow = args.row
api
.fetch('/udf/setExpire', {udfId: this.handleRow.id}, 'post')
.then(() => {
this.$Message.success(this.$t('message.linkis.editedSuccess'))
this.search()
})
.catch(() => {
})
},
changeUser(args) {
if (!this.changUserModal && args) {
this.handleUser = ''
this.changUserModal = true
this.handleRow = args.row
api.fetch('/dss/framework/workspace/listAllUsers', 'get').then(res => {
let allUsers = (res.users || []).map(it => it.username)
this.udfUsers = allUsers.slice(0, 150)
this.allUsers = allUsers
}).catch(()=>{
this.udfUsers = [];
this.allUsers = [];
})
} else {
const params = {
udfId: this.handleRow.id,
handoverUser: this.handleUser
}
this.changUserModal = false
api
.fetch('/udf/handover', params, 'post')
.then(() => {
this.$Message.success(this.$t('message.linkis.editedSuccess'))
this.search()
})
.catch(() => {
})
}
},
confirmKillIdle() {
this.$Modal.confirm({
title: this.$t('message.linkis.setting.killEngineTitle'),
content: this.$t('message.linkis.setting.killEngine'),
onOk: async () => {
try {
api.fetch("/linkisManager/rm/killEngineByCreatorEngineType", {
creator: '*',
engineType: 'spark'
})
} catch (err) {
window.console.warn(err)
}
}
})
},
getShareUsers() {
return api.fetch('/udf/getSharedUsers', {udfId: this.handleRow.id}, 'post')
},
filterSelect(query) {
let options = this.allUsers.filter(it=> it.indexOf(query) > -1).slice(0, 150)
this.udfUsers = options
return new Promise((resolve)=>{
resolve(options)
})
},
filterNode(node) {
const name = node.label;
const tabSuffix = name.substr(name.lastIndexOf('.'), name.length);
return !node.isLeaf || (node.isLeaf && (tabSuffix === '.py' || tabSuffix === '.scala'));
},
queryChange(q) {
if (!q) {
this.changUserModalChange(true)
}
},
vModalChange(v) {
if (v===false) {
this.handleRow = {}
}
},
changUserModalChange(v) {
if (v) {
this.$refs.userSelect && this.$refs.userSelect.setQuery(null);
this.handleUser = ''
let options = this.allUsers.slice(0, 150)
this.udfUsers = options
}
}
}
}
</script>
<style src="./index.scss" lang="scss"></style>