feat(user): user manage

This commit is contained in:
dataeaseShu
2025-07-16 18:11:49 +08:00
parent 07884b2a72
commit 530545ddab
13 changed files with 435 additions and 105 deletions
+1 -1
View File
@@ -24,5 +24,5 @@ export const userApi = {
delete: (key: string) => request.delete(`/user/${key}`),
deleteBatch: (data: any) => request.delete(`/user`, { data }),
get: (key: string) => request.get(`/user/${key}`),
pwd: (data: any) => request.put('/user/pwd', data),
pwd: (id: any) => request.patch(`/user/pwd/${id}`),
}
+9 -3
View File
@@ -24,7 +24,11 @@
"simplified_chinese": "Simplified Chinese",
"traditional_chinese": "Traditional Chinese",
"help": "Help",
"language": "Language"
"language": "Language",
"re_upload": "Re-upload",
"not_exceed_50mb": "Supports XLS, XLSX, CSV formats, file size does not exceed 50MB",
"reset_password": "Reset password",
"password_reset_successful": "Password reset successful"
},
"dashboard": {
"select_dashboard": "Please Select Dashboard",
@@ -186,7 +190,9 @@
"operate_with_caution": "After being deleted, the data source cannot be intelligently counted. Please operate with caution.",
"data_source_de": "Unable to delete data source: {msg}",
"cannot_be_deleted": "The chart of the dashboard uses this data source and cannot be deleted.",
"got_it": "Got it"
"got_it": "Got it",
"field_original_notes": "Field original notes",
"field_notes_1": "Field notes"
},
"model": {
"default_model": "Default model",
@@ -330,4 +336,4 @@
"back_community": "Restore to Community Edition",
"confirm_tips": "Are you sure to restore to Community Edition?"
}
}
}
+10 -4
View File
@@ -26,7 +26,11 @@
"simplified_chinese": "简体中文",
"traditional_chinese": "繁體中文",
"help": "帮助",
"language": "语言"
"language": "语言",
"re_upload": "重新上传",
"not_exceed_50mb": "支持 XLS、XLSX、CSV 格式,文件大小不超过 50MB",
"reset_password": "重置密码",
"password_reset_successful": "重置密码成功"
},
"dashboard": {
"select_dashboard": "请选择仪表板",
@@ -124,14 +128,14 @@
"choose_tables": "选择数据表",
"name": "名称",
"description": "描述",
"host": "主机/IP",
"host": "主机名/IP地址",
"port": "端口",
"username": "用户名",
"password": "密码",
"database": "数据库",
"connect_mode": "连接方式",
"service_name": "服务名",
"extra_jdbc": "额外 JDBC 参数",
"extra_jdbc": "额外的 JDBC 连接字符串",
"schema": "模式",
"get_schema": "获取模式",
"file": "文件",
@@ -194,7 +198,9 @@
"operate_with_caution": "被删除后,将无法对该数据源进行智能问数,请谨慎操作。",
"data_source_de": "无法删除数据源:{msg}",
"cannot_be_deleted": "仪表板的图表使用了该数据源,不可删除。",
"got_it": "知道了"
"got_it": "知道了",
"field_original_notes": "字段原始备注",
"field_notes_1": "字段备注"
},
"model": {
"default_model": "默认模型",
+3
View File
@@ -27,6 +27,9 @@
--ed-color-primary: #1cba90 !important;
--ed-border-radius-base: 6px !important;
--ed-color-primary-light-3: #3ec4a1 !important;
--ed-color-primary-dark-2: #189e7a !important;
--ed-color-primary-1a: #1cba901a;
}
a {
+26
View File
@@ -54,3 +54,29 @@ export const getBrowserLocale = () => {
export const getLocale = () => {
return wsCache.get('user.language') || getBrowserLocale() || 'zh-CN'
}
export const setSize = (size: any) => {
let data = ''
const _size = Number.parseFloat(size)
if (_size < 1 * 1024) {
//如果小于0.1KB转化成B
data = _size.toFixed(2) + 'B'
} else if (_size < 1 * 1024 * 1024) {
//如果小于0.1MB转化成KB
data = (_size / 1024).toFixed(2) + 'KB'
} else if (_size < 1 * 1024 * 1024 * 1024) {
//如果小于0.1GB转化成MB
data = (_size / (1024 * 1024)).toFixed(2) + 'MB'
} else {
//其他转化成GB
data = (_size / (1024 * 1024 * 1024)).toFixed(2) + 'GB'
}
const size_str = data + ''
const len = size_str.indexOf('.')
const dec = size_str.substr(len + 1, 2)
if (dec == '00') {
//当小数点后为00时 去掉小数部分
return size_str.substring(0, len) + size_str.substr(len + 3, 2)
}
return size_str
}
+72 -31
View File
@@ -52,6 +52,7 @@ const props = withDefaults(
const { t } = useI18n()
const paramsFormRef = ref()
const tableList = ref([] as any[])
const loading = ref(false)
const keywords = ref('')
const tableListWithSearch = computed(() => {
if (!keywords.value) return tableList.value
@@ -63,7 +64,7 @@ const total = ref(1000)
const showNum = ref(100)
const currentTable = ref<any>({})
const ds = ref<any>({})
const btnSelect = ref('q')
const btnSelect = ref('d')
const init = () => {
datasourceApi.getDs(props.info.id).then((res) => {
@@ -94,13 +95,19 @@ const handleSelectTableList = () => {
}
const clickTable = (table: any) => {
loading.value = true
currentTable.value = table
datasourceApi.fieldList(table.id).then((res) => {
fieldList.value = res
datasourceApi.previewData(props.info.id, buildData()).then((res) => {
previewData.value = res
datasourceApi
.fieldList(table.id)
.then((res) => {
fieldList.value = res
datasourceApi.previewData(props.info.id, buildData()).then((res) => {
previewData.value = res
})
})
.finally(() => {
loading.value = false
})
})
}
const closeTable = () => {
@@ -228,12 +235,14 @@ const back = () => {
</div>
</div>
<div v-if="currentTable.table_name" class="info-table">
<div v-if="currentTable.table_name" v-loading="loading" class="info-table">
<div class="table-name">
<div class="name">{{ currentTable.table_name }}</div>
<div class="notes">
{{ $t('about.remark') }}:
{{ currentTable.custom_comment || '-' }}
<span :title="currentTable.custom_comment" class="field-notes">{{
currentTable.custom_comment || '-'
}}</span>
<el-icon style="margin-left: 8px; cursor: pointer" size="16" @click="editTable">
<edit></edit>
</el-icon>
@@ -253,11 +262,13 @@ const back = () => {
<el-table v-if="btnSelect === 'd'" :data="fieldList" style="width: 100%">
<el-table-column prop="field_name" :label="t('datasource.field_name')" width="180" />
<el-table-column prop="field_type" :label="t('datasource.field_type')" width="180" />
<el-table-column prop="field_comment" :label="t('about.remark')" />
<el-table-column :label="t('datasource.custom_notes')">
<el-table-column prop="field_comment" :label="t('datasource.field_original_notes')" />
<el-table-column :label="t('datasource.field_notes_1')">
<template #default="scope">
<div class="field-comment">
<span>{{ scope.row.custom_comment }}</span>
<span :title="scope.row.custom_comment" class="notes-in_table">{{
scope.row.custom_comment
}}</span>
<el-tooltip
:offset="14"
effect="dark"
@@ -441,6 +452,7 @@ const back = () => {
right: 0;
top: 0;
width: calc(100% - 280px);
height: 100%;
.table-name {
height: 80px;
padding: 16px 0 0 24px;
@@ -459,11 +471,20 @@ const back = () => {
color: #646a73;
display: flex;
align-items: center;
.field-notes {
display: inline-block;
max-width: calc(100% - 75px);
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
}
.table-content {
padding: 16px 24px;
height: calc(100% - 80px);
.btn-select {
height: 32px;
@@ -495,33 +516,53 @@ const back = () => {
.preview-or-schema {
margin-top: 16px;
height: calc(100% - 50px);
overflow-y: auto;
.field-comment {
height: 24px;
}
.ed-icon {
position: relative;
cursor: pointer;
margin-top: 4px;
&::after {
content: '';
background-color: #1f23291a;
position: absolute;
border-radius: 6px;
width: 24px;
height: 24px;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
display: none;
display: flex;
align-items: center;
min-height: 24px;
.notes-in_table {
max-width: 192px;
display: -webkit-box;
max-height: 66px;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* 限制行数为3 */
overflow: hidden;
text-overflow: ellipsis;
}
&:hover {
&::after {
.ed-icon {
display: block;
}
}
.ed-icon {
position: relative;
cursor: pointer;
margin-top: 4px;
margin-left: 8px;
display: none;
&::after {
content: '';
background-color: #1f23291a;
position: absolute;
border-radius: 6px;
width: 24px;
height: 24px;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
display: none;
}
&:hover {
&::after {
display: block;
}
}
}
}
.preview-num {
+1
View File
@@ -324,6 +324,7 @@ const back = () => {
<DatasourceForm
v-if="[1, 2].includes(activeStep)"
ref="datasourceFormRef"
:isDataTable="false"
:active-step="activeStep"
:active-name="activeName"
:active-type="activeType"
+261 -47
View File
@@ -2,6 +2,7 @@
import { ref, reactive, onMounted, computed, watch, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import { datasourceApi } from '@/api/datasource'
import icon_upload_outlined from '@/assets/svg/icon_upload_outlined.svg'
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
import { encrypted, decrypted } from './js/aes'
import { ElMessage } from 'element-plus-secondary'
@@ -11,18 +12,23 @@ import FixedSizeList from 'element-plus-secondary/es/components/virtual-list/src
import { Plus } from '@element-plus/icons-vue'
import { useCache } from '@/utils/useCache'
import { dsType, haveSchema } from '@/views/ds/js/ds-type'
import { setSize } from '@/utils/utils'
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
import icon_fileExcel_colorful from '@/assets/datasource/icon_excel.png'
import IconOpeDelete from '@/assets/svg/icon_delete.svg'
const props = withDefaults(
defineProps<{
activeName: string
activeType: string
activeStep: number
isDataTable: boolean
}>(),
{
activeName: '',
activeType: '',
activeStep: 0,
isDataTable: false,
}
)
@@ -44,20 +50,55 @@ const headers = ref<any>({ 'X-SQLBOT-TOKEN': `Bearer ${token}`, 'X-SQLBOT-KEY':
const dialogTitle = ref('')
const getUploadURL = import.meta.env.VITE_API_BASE_URL + '/datasource/uploadExcel'
const saveLoading = ref<boolean>(false)
const uploadLoading = ref(false)
const { t } = useI18n()
const rules = reactive<FormRules>({
name: [
{ required: true, message: t('ds.form.validate.name_required'), trigger: 'blur' },
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('ds.form.name'),
trigger: 'blur',
},
{ min: 1, max: 50, message: t('ds.form.validate.name_length'), trigger: 'blur' },
],
type: [{ required: true, message: t('ds.form.validate.type_required'), trigger: 'change' }],
host: [{ required: true, message: 'Please input host', trigger: 'blur' }],
port: [{ required: true, message: 'Please input port', trigger: 'blur' }],
database: [{ required: true, message: 'Please input database', trigger: 'blur' }],
type: [
{
required: true,
message: t('datasource.Please_select') + t('common.empty') + t('ds.type'),
trigger: 'change',
},
],
host: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('ds.form.port'),
trigger: 'blur',
},
],
port: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('ds.form.host'),
trigger: 'blur',
},
],
database: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('ds.form.database'),
trigger: 'blur',
},
],
mode: [{ required: true, message: 'Please choose mode', trigger: 'change' }],
dbSchema: [{ required: true, message: 'Please input schema', trigger: 'blur' }],
sheets: [{ required: true, message: t('user.upload_file'), trigger: 'change' }],
dbSchema: [
{
required: true,
message: t('datasource.please_enter') + t('common.empty') + t('ds.form.schema'),
trigger: 'blur',
},
],
})
const dialogVisible = ref<boolean>(false)
@@ -312,10 +353,12 @@ const preview = () => {
}
const beforeUpload = (rawFile: any) => {
setFile(rawFile)
if (rawFile.size / 1024 / 1024 > 50) {
ElMessage.error('File size can not exceed 50MB!')
ElMessage.error(t('common.not_exceed_50mb'))
return false
}
uploadLoading.value = true
return true
}
@@ -324,6 +367,11 @@ const onSuccess = (response: any) => {
form.value.sheets = response.data.sheets
tableList.value = response.data.sheets
excelUploadSuccess.value = true
uploadLoading.value = false
}
const onError = () => {
uploadLoading.value = false
}
onMounted(() => {
@@ -354,6 +402,17 @@ watch(
form.value.type = val
}
)
const fileSize = ref('-')
const clearFile = () => {
fileSize.value = ''
form.value.filename = ''
form.value.sheets = []
tableList.value = []
}
const setFile = (file: any) => {
fileSize.value = setSize(file.size)
}
const checkAll = ref(false)
const isIndeterminate = ref(false)
@@ -396,9 +455,12 @@ defineExpose({
</script>
<template>
<div class="model-form" :class="(!isCreate || activeStep === 2) && 'edit-form'">
<div
class="model-form"
v-loading="uploadLoading"
:class="(!isCreate || activeStep === 2) && 'edit-form'"
>
<div v-if="isCreate && activeStep !== 2" class="model-name">{{ activeName }}</div>
<div class="form-content">
<el-form
v-show="activeStep === 1"
@@ -408,14 +470,78 @@ defineExpose({
label-width="auto"
:rules="rules"
>
<div v-if="form.type === 'excel'">
<el-form-item prop="sheets" :label="t('ds.form.file')">
<div v-if="form.filename" class="pdf-card">
<img :src="icon_fileExcel_colorful" width="40px" height="40px" />
<div class="file-name">
<div class="name">{{ form.filename }}</div>
<div class="size">{{ form.filename.split('.')[1] }} - {{ fileSize }}</div>
</div>
<el-icon class="action-btn" size="16" @click="clearFile">
<IconOpeDelete></IconOpeDelete>
</el-icon>
</div>
<el-upload
v-if="form.filename"
class="upload-user"
accept=".xlsx,.xls"
:headers="headers"
:action="getUploadURL"
:before-upload="beforeUpload"
:on-error="onError"
:on-success="onSuccess"
:show-file-list="false"
:file-list="form.sheets"
>
<el-button text style="line-height: 22px; height: 22px">
{{ $t('common.re_upload') }}
</el-button>
</el-upload>
<el-upload
v-else
class="upload-user"
accept=".xlsx,.xls"
:headers="headers"
:action="getUploadURL"
:before-upload="beforeUpload"
:on-success="onSuccess"
:on-error="onError"
:show-file-list="false"
:file-list="form.sheets"
>
<el-button secondary>
<el-icon size="16" style="margin-right: 4px">
<icon_upload_outlined></icon_upload_outlined>
</el-icon>
{{ t('user.upload_file') }}</el-button
>
</el-upload>
<span v-if="!form.filename" class="not_exceed">{{ $t('common.not_exceed_50mb') }}</span>
</el-form-item>
</div>
<el-form-item :label="t('ds.form.name')" prop="name">
<el-input v-model="form.name" />
<el-input
:placeholder="$t('datasource.please_enter') + $t('common.empty') + t('ds.form.name')"
v-model="form.name"
/>
</el-form-item>
<el-form-item :label="t('ds.form.description')">
<el-input v-model="form.description" :rows="2" type="textarea" />
<el-input
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + t('ds.form.description')
"
v-model="form.description"
:rows="2"
type="textarea"
/>
</el-form-item>
<el-form-item :label="t('ds.type')" prop="type">
<el-select v-model="form.type" placeholder="Select Type" :disabled="!isCreate">
<el-select
v-model="form.type"
:placeholder="$t('datasource.Please_select') + $t('common.empty') + t('ds.type')"
:disabled="!isCreate"
>
<el-option
v-for="item in dsType"
:key="item.value"
@@ -424,38 +550,52 @@ defineExpose({
/>
</el-select>
</el-form-item>
<div v-if="form.type === 'excel'">
<el-form-item label="File">
<el-upload
:disabled="!isCreate"
accept=".xls, .xlsx, .csv"
:headers="headers"
:action="getUploadURL"
:before-upload="beforeUpload"
:on-success="onSuccess"
>
<el-button :disabled="!isCreate">{{ t('ds.form.upload.button') }}</el-button>
<template #tip>
<div class="el-upload__tip">{{ t('ds.form.upload.tip') }}</div>
</template>
</el-upload>
</el-form-item>
</div>
<div v-else>
<span v-if="form.type !== 'excel'">
<span>{{ t('ds.form.support_version') }}:&nbsp;</span>
<span v-if="form.type === 'sqlServer'">2012+</span>
<span v-else-if="form.type === 'oracle'">12+</span>
<span v-else-if="form.type === 'mysql'">5.6+</span>
<span v-else-if="form.type === 'pg'">9.6+</span>
</span>
<div style="margin-top: 16px" v-if="form.type !== 'excel'">
<el-form-item :label="t('ds.form.host')" prop="host">
<el-input v-model="form.host" />
<el-input
:placeholder="$t('datasource.please_enter') + $t('common.empty') + t('ds.form.host')"
v-model="form.host"
/>
</el-form-item>
<el-form-item :label="t('ds.form.port')" prop="port">
<el-input v-model="form.port" />
<el-input
:placeholder="$t('datasource.please_enter') + $t('common.empty') + t('ds.form.port')"
v-model="form.port"
/>
</el-form-item>
<el-form-item :label="t('ds.form.username')">
<el-input v-model="form.username" />
<el-input
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + t('ds.form.username')
"
v-model="form.username"
/>
</el-form-item>
<el-form-item :label="t('ds.form.password')">
<el-input v-model="form.password" type="password" show-password />
<el-input
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + t('ds.form.password')
"
v-model="form.password"
type="password"
show-password
/>
</el-form-item>
<el-form-item :label="t('ds.form.database')" prop="database">
<el-input v-model="form.database" />
<el-input
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + t('ds.form.database')
"
v-model="form.database"
/>
</el-form-item>
<el-form-item
v-if="form.type === 'oracle'"
@@ -468,26 +608,29 @@ defineExpose({
</el-radio-group>
</el-form-item>
<el-form-item :label="t('ds.form.extra_jdbc')">
<el-input v-model="form.extraJdbc" />
<el-input
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + t('ds.form.extra_jdbc')
"
v-model="form.extraJdbc"
/>
</el-form-item>
<el-form-item
v-if="haveSchema.includes(form.type)"
:label="t('ds.form.schema')"
prop="dbSchema"
>
<el-input v-model="form.dbSchema" />
<el-input
:placeholder="
$t('datasource.please_enter') + $t('common.empty') + t('ds.form.schema')
"
v-model="form.dbSchema"
/>
<el-button v-if="false" link type="primary" :icon="Plus">Get Schema</el-button>
</el-form-item>
<el-form-item :label="t('ds.form.timeout')" prop="timeout">
<el-input-number v-model="form.timeout" :min="0" :max="300" controls-position="right" />
</el-form-item>
<span>
<span>{{ t('ds.form.support_version') }}:&nbsp;</span>
<span v-if="form.type === 'sqlServer'">2012+</span>
<span v-else-if="form.type === 'oracle'">12+</span>
<span v-else-if="form.type === 'mysql'">5.6+</span>
<span v-else-if="form.type === 'pg'">9.6+</span>
</span>
</div>
</el-form>
<div v-show="activeStep === 2" v-loading="tableListLoading" class="select-data_table">
@@ -554,8 +697,8 @@ defineExpose({
</div>
</div>
<div class="draw-foot">
<el-button @click="close">{{ t('common.cancel') }}</el-button>
<el-button v-show="form.type !== 'excel'" @click="check">
<el-button secondary @click="close">{{ t('common.cancel') }}</el-button>
<el-button v-show="form.type !== 'excel' && !isDataTable" @click="check">
{{ t('ds.check') }}
</el-button>
<el-button v-show="activeStep !== 0 && isCreate" secondary @click="preview">
@@ -602,6 +745,77 @@ defineExpose({
margin: 0 auto;
padding-top: 24px;
.upload-user {
height: 32px;
.ed-upload {
width: 100% !important;
}
}
.not_exceed {
font-weight: 400;
font-size: 14px;
line-height: 22px;
color: #8f959e;
display: inline-block;
width: 100%;
}
.pdf-card {
width: 100%;
height: 58px;
display: flex;
align-items: center;
padding: 0 16px 0 12px;
border: 1px solid #dee0e3;
border-radius: 6px;
.file-name {
margin-left: 8px;
.name {
font-weight: 400;
font-size: 14px;
line-height: 22px;
}
.size {
font-weight: 400;
font-size: 12px;
line-height: 20px;
color: #8f959e;
}
}
.action-btn {
margin-left: auto;
}
.ed-icon {
position: relative;
cursor: pointer;
color: #646a73;
&::after {
content: '';
background-color: #1f23291a;
position: absolute;
border-radius: 6px;
width: 24px;
height: 24px;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
display: none;
}
&:hover {
&::after {
display: block;
}
}
}
}
.ed-form-item--default {
margin-bottom: 16px;
+1
View File
@@ -55,6 +55,7 @@ defineExpose({
:active-step="2"
active-name=""
active-type=""
isDataTable
@change-active-step="changeActiveStep"
@refresh="refresh"
></DatasourceForm>
+11 -4
View File
@@ -101,10 +101,12 @@ const formatKeywords = (item: string) => {
}
const handleAddModel = () => {
activeStep.value = 0
editModel.value = false
modelConfigvVisible.value = true
}
const handleEditModel = (row: any) => {
activeStep.value = 1
editModel.value = true
activeType.value = row.supplier
activeName.value = row.supplier_item.name
modelApi.query(row.id).then((res: any) => {
@@ -304,7 +306,9 @@ const submit = (item: any) => {
:show-close="false"
>
<template #header="{ close }">
<span style="white-space: nowrap">{{ t('model.add_model') }}</span>
<span style="white-space: nowrap">{{
editModel ? $t('dashboard.edit') + $t('common.empty') + activeName : t('model.add_model')
}}</span>
<div v-if="!editModel" class="flex-center" style="width: 100%">
<el-steps custom style="max-width: 500px; flex: 1" :active="activeStep" align-center>
<el-step>
@@ -321,7 +325,7 @@ const submit = (item: any) => {
</template>
<ModelList v-if="activeStep === 0" @click-model="clickModel"></ModelList>
<ModelListSide
v-if="activeStep === 1"
v-if="activeStep === 1 && !editModel"
:active-name="activeName"
:active-type="activeType"
@click-model="supplierChang"
@@ -331,11 +335,14 @@ const submit = (item: any) => {
ref="modelFormRef"
:active-name="activeName"
:active-type="activeType"
:edit-model="editModel"
@submit="submit"
></ModelForm>
<template #footer>
<template v-if="activeStep !== 0" #footer>
<el-button secondary @click="cancel"> {{ $t('common.cancel') }} </el-button>
<el-button secondary @click="preStep"> {{ $t('ds.previous') }} </el-button>
<el-button v-if="!editModel" secondary @click="preStep">
{{ $t('ds.previous') }}
</el-button>
<el-button type="primary" @click="saveModel"> {{ $t('common.save') }} </el-button>
</template>
</el-drawer>
@@ -13,9 +13,11 @@ import { useI18n } from 'vue-i18n'
withDefaults(
defineProps<{
activeName: string
editModel: boolean
}>(),
{
activeName: '',
editModel: false,
}
)
@@ -166,8 +168,8 @@ defineExpose({
</script>
<template>
<div class="model-form">
<div class="model-name">{{ activeName }}</div>
<div class="model-form" :class="editModel && 'is-edit_model'">
<div class="model-name" v-if="!editModel">{{ activeName }}</div>
<div class="form-content">
<el-form
ref="modelRef"
@@ -310,6 +312,10 @@ defineExpose({
right: 0;
top: 56px;
height: 100%;
&.is-edit_model {
width: 100%;
}
.model-name {
height: 56px;
width: 100%;
+22 -12
View File
@@ -98,7 +98,7 @@
<el-tooltip
:offset="14"
effect="dark"
:content="$t('user.change_password')"
:content="$t('common.reset_password')"
placement="top"
>
<el-icon class="action-btn" size="16" @click="handleEditPassword(scope.row.id)">
@@ -205,6 +205,7 @@
<el-form-item :label="$t('user.workspace')">
<el-select
clearable
v-model="state.form.oid"
:placeholder="$t('datasource.Please_select') + $t('common.empty') + $t('user.workspace')"
>
@@ -218,7 +219,9 @@
<template #footer>
<div class="dialog-footer">
<el-button @click="closeForm">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" @click="saveHandler"> {{ $t('model.add') }} </el-button>
<el-button type="primary" @click="saveHandler">
{{ state.form.id ? $t('common.save') : $t('model.add') }}
</el-button>
</div>
</template>
</el-drawer>
@@ -315,13 +318,13 @@ const filterOption = ref<any[]>([
type: 'enum',
option: [
{ id: '0', name: t('user.local_creation') },
{ id: 1, name: 'LDAP' },
{ id: 2, name: 'OIDC' },
{ id: 3, name: 'CAS' },
{ id: 9, name: 'OAuth2' },
{ id: 4, name: t('user.feishu') },
{ id: 5, name: t('user.dingtalk') },
{ id: 6, name: t('user.wechat_for_business') },
// { id: 1, name: 'LDAP' },
// { id: 2, name: 'OIDC' },
// { id: 3, name: 'CAS' },
// { id: 9, name: 'OAuth2' },
// { id: 4, name: t('user.feishu') },
// { id: 5, name: t('user.dingtalk') },
// { id: 6, name: t('user.wechat_for_business') },
],
field: 'origins',
title: t('user.user_source'),
@@ -330,7 +333,7 @@ const filterOption = ref<any[]>([
{
type: 'select',
option: [],
field: 'oidist',
field: 'oidlist',
title: t('user.workspace'),
operate: 'in',
property: { placeholder: t('common.empty') + t('user.workspace') },
@@ -412,8 +415,12 @@ const handleClosePassword = () => {
}
const handleEditPassword = (id: any) => {
password.value.id = id
dialogVisiblePassword.value = true
userApi.pwd(id).then(() => {
ElMessage({
type: 'success',
message: t('common.password_reset_successful'),
})
})
}
const handleUserImport = () => {
@@ -576,6 +583,9 @@ const configParams = () => {
}
state.conditions.forEach((ele: any) => {
if (ele.field === 'status' && ele.value.length === 2) {
return
}
ele.value.forEach((itx: any) => {
str += str ? `&${ele.field}=${itx}` : `${ele.field}=${itx}`
})
@@ -26,7 +26,7 @@
</el-icon>
</template>
</el-input>
<div class="mt-8">
<div class="mt-8 max-height_workspace">
<el-checkbox
v-if="!search"
v-model="checkAll"
@@ -129,6 +129,9 @@ let oid: any = null
const open = async (id: any) => {
loading.value = true
oid = id
checkedWorkspace.value = []
checkAll.value = false
isIndeterminate.value = false
const systemWorkspaceList = await workspaceOptionUserList({ oid }, 1, 1000)
workspace.value = systemWorkspaceList.items as any
loading.value = false
@@ -201,6 +204,7 @@ defineExpose({
.w-full {
width: 100%;
overflow-y: auto;
.flex-between {
height: 44px;
@@ -211,6 +215,11 @@ defineExpose({
margin-top: 8px;
}
.max-height_workspace {
max-height: calc(100% - 24px);
overflow-y: auto;
}
.align-center {
align-items: center;
}