|
|
@@ -2,6 +2,7 @@
|
|
|
import { useRouter } from 'vue-router'
|
|
|
import partyIDSelect from './components/partyIDSelect.vue'
|
|
|
import GroupNameSelect from './components/GroupNameSelect.vue'
|
|
|
+import { VueDraggable } from 'vue-draggable-plus'
|
|
|
|
|
|
const router = useRouter()
|
|
|
const filterRef: Ref<HTMLElement | null> = ref(null)
|
|
|
@@ -31,7 +32,19 @@ const handleCreate = () => {
|
|
|
router.push('/create-report-template')
|
|
|
}
|
|
|
|
|
|
-const fieldsList = ref([])
|
|
|
+interface Field {
|
|
|
+ field: string
|
|
|
+ title: string
|
|
|
+ displayName: string
|
|
|
+ value?: string
|
|
|
+ isFilter: boolean
|
|
|
+ isSort: boolean
|
|
|
+}
|
|
|
+const fieldsList = ref<Field[]>([])
|
|
|
+
|
|
|
+const handleDeleteField = (field: string) => {
|
|
|
+ fieldsList.value = fieldsList.value.filter((item) => item.field !== field)
|
|
|
+}
|
|
|
|
|
|
const CustomizeColumnsRef = ref()
|
|
|
// 打开定制表格弹窗
|
|
|
@@ -62,10 +75,49 @@ const customizeColumns = async () => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-const radioa = ref('1')
|
|
|
+const newFieldInfo = ref<{
|
|
|
+ name: string
|
|
|
+ fieldType: 'Blank' | 'Fixed Value'
|
|
|
+ value: string
|
|
|
+}>({
|
|
|
+ name: '',
|
|
|
+ fieldType: 'Blank',
|
|
|
+ value: ''
|
|
|
+})
|
|
|
+const addNewFieldVisible = ref(false)
|
|
|
+// 添加新字段
|
|
|
+const handleAddNewField = () => {
|
|
|
+ addNewFieldVisible.value = true
|
|
|
+}
|
|
|
+const handleFieldTypeChange = () => {
|
|
|
+ newFieldInfo.value.value = ''
|
|
|
+}
|
|
|
+const addNewField = () => {
|
|
|
+ if (newFieldInfo.value.name) {
|
|
|
+ fieldsList.value.push({
|
|
|
+ field: newFieldInfo.value.name,
|
|
|
+ title: newFieldInfo.value.name,
|
|
|
+ value: newFieldInfo.value.value,
|
|
|
+ displayName: '',
|
|
|
+ isFilter: false,
|
|
|
+ isSort: false
|
|
|
+ })
|
|
|
+ newFieldInfo.value = {
|
|
|
+ name: '',
|
|
|
+ fieldType: 'Blank',
|
|
|
+ value: ''
|
|
|
+ }
|
|
|
+ addNewFieldVisible.value = false
|
|
|
+ } else {
|
|
|
+ ElMessage.warning('Please enter the new field name.')
|
|
|
+ return
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const reportAccessControlRadio = ref('All Users')
|
|
|
const detailRef: Ref<HTMLElement | null> = ref(null)
|
|
|
-watch(radioa, (newVal) => {
|
|
|
- if (newVal === '2') {
|
|
|
+watch(reportAccessControlRadio, (newVal) => {
|
|
|
+ if (newVal === 'Specific Roles') {
|
|
|
// 等待下一个渲染周期结束后,获取detailRef的高度
|
|
|
nextTick(() => {
|
|
|
if (detailRef.value) {
|
|
|
@@ -77,6 +129,9 @@ watch(radioa, (newVal) => {
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
+
|
|
|
+const loading = ref(false)
|
|
|
+const handleRightRemove = () => {}
|
|
|
</script>
|
|
|
<template>
|
|
|
<div class="dashboard">
|
|
|
@@ -133,14 +188,26 @@ watch(radioa, (newVal) => {
|
|
|
<div class="fields-configuration template-box">
|
|
|
<div class="header">
|
|
|
<span>Report Fields Configuration</span>
|
|
|
- <el-button
|
|
|
- v-if="fieldsList.length > 0"
|
|
|
- class="el-button--dark"
|
|
|
- @click="handleCustomizeColumns"
|
|
|
- style="margin-left: auto; width: 110px; padding-top: 11px"
|
|
|
- >
|
|
|
- <span style="margin-right: 3px" class="font_family icon-icon_add_b"></span>Add Field
|
|
|
- </el-button>
|
|
|
+
|
|
|
+ <div class="right-option">
|
|
|
+ <el-button
|
|
|
+ class="el-button--dark"
|
|
|
+ @click="handleAddNewField"
|
|
|
+ style="width: 148px; padding-top: 11px"
|
|
|
+ >
|
|
|
+ <span style="margin-right: 3px" class="font_family icon-icon_add_b"></span>
|
|
|
+ <span>Add New Field</span>
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ v-if="fieldsList.length > 0"
|
|
|
+ class="el-button--dark"
|
|
|
+ @click="handleCustomizeColumns"
|
|
|
+ style="width: 110px; padding-top: 11px"
|
|
|
+ >
|
|
|
+ <span style="margin-right: 3px" class="font_family icon-icon_add_b"></span>
|
|
|
+ <span>Select Field</span>
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
<div class="content-box">
|
|
|
<div class="empty-box" v-if="fieldsList.length === 0">
|
|
|
@@ -150,25 +217,53 @@ watch(radioa, (newVal) => {
|
|
|
<p>No field selected. click “Add Field” to get started.</p>
|
|
|
</div>
|
|
|
<div class="fields-list" v-else>
|
|
|
- <div class="field-item" v-for="(field, index) in fieldsList" :key="index">
|
|
|
- <div class="label">
|
|
|
- <span style="font-weight: 700">[{{ field.title }}]</span>
|
|
|
- <span style="margin-left: 8px">{{ field.field }}</span>
|
|
|
- </div>
|
|
|
- <el-input class="display-name" placeholder="Display Name in Report"></el-input>
|
|
|
- <div class="actions">
|
|
|
- <div><el-checkbox>Filter</el-checkbox> <el-checkbox>Sort</el-checkbox></div>
|
|
|
- <span class="font_family icon-icon_delete_b"></span>
|
|
|
+ <VueDraggable
|
|
|
+ v-vloading="loading"
|
|
|
+ v-model="fieldsList"
|
|
|
+ class="column-list"
|
|
|
+ ghost-class="ghost-column"
|
|
|
+ :forceFallback="true"
|
|
|
+ fallback-class="fallback-class"
|
|
|
+ group="customizeColumns"
|
|
|
+ item-key="field"
|
|
|
+ @end="handleRightRemove"
|
|
|
+ >
|
|
|
+ <div class="field-item" v-for="fieldItem in fieldsList" :key="fieldItem.field">
|
|
|
+ <span
|
|
|
+ class="font_family icon-icon_dragsort__b draggable-icon"
|
|
|
+ style="margin-right: 12px; font-size: 16px"
|
|
|
+ ></span>
|
|
|
+ <div class="label">
|
|
|
+ <span style="font-weight: 700">[{{ fieldItem.title }}]</span>
|
|
|
+ <span style="margin-left: 8px">{{
|
|
|
+ fieldItem.displayName || fieldItem.title
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+ <el-input
|
|
|
+ class="display-name"
|
|
|
+ v-model="fieldItem.displayName"
|
|
|
+ placeholder="Display Name in Report"
|
|
|
+ ></el-input>
|
|
|
+ <div class="actions">
|
|
|
+ <div>
|
|
|
+ <el-checkbox v-model="fieldItem.isFilter">Filter</el-checkbox>
|
|
|
+ <el-checkbox v-model="fieldItem.isSort">Sort</el-checkbox>
|
|
|
+ </div>
|
|
|
+ <span
|
|
|
+ @click="handleDeleteField(fieldItem.field)"
|
|
|
+ class="font_family icon-icon_delete_b"
|
|
|
+ ></span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ </VueDraggable>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="report-access-control template-box">
|
|
|
<div class="header">Report Access Control</div>
|
|
|
<div class="content-box">
|
|
|
- <el-radio-group class="radio-group" v-model="radioa">
|
|
|
- <el-radio class="radio-item" value="1">
|
|
|
+ <el-radio-group class="radio-group" v-model="reportAccessControlRadio">
|
|
|
+ <el-radio class="radio-item" value="All Users">
|
|
|
<template #default>
|
|
|
<div class="radio-content">
|
|
|
<p class="label">All Users</p>
|
|
|
@@ -178,14 +273,18 @@ watch(radioa, (newVal) => {
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-radio>
|
|
|
- <el-radio class="radio-item specific-roles" value="2">
|
|
|
+ <el-radio class="radio-item specific-roles" value="Specific Roles">
|
|
|
<template #default>
|
|
|
<div class="radio-content">
|
|
|
<div class="top-options">
|
|
|
<p class="label">Specific Roles</p>
|
|
|
<p class="description">Restrict access to specific user roles</p>
|
|
|
</div>
|
|
|
- <div class="extended-filter" v-if="radioa === '2'" ref="detailRef">
|
|
|
+ <div
|
|
|
+ class="extended-filter"
|
|
|
+ v-if="reportAccessControlRadio === 'Specific Roles'"
|
|
|
+ ref="detailRef"
|
|
|
+ >
|
|
|
<div class="dividing-line"></div>
|
|
|
<div class="filter-item" style="margin-bottom: 16px">
|
|
|
<div class="label">
|
|
|
@@ -209,7 +308,53 @@ watch(radioa, (newVal) => {
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
<CustomizeColumns @customize="customizeColumns" ref="CustomizeColumnsRef" />
|
|
|
+ <el-dialog
|
|
|
+ class="add-new-field-dialog"
|
|
|
+ title="Add New Field"
|
|
|
+ v-model="addNewFieldVisible"
|
|
|
+ width="480"
|
|
|
+ >
|
|
|
+ <div>
|
|
|
+ <div class="field-item">
|
|
|
+ <div class="label">
|
|
|
+ <span class="required-symbol">*</span>
|
|
|
+ <span>New Field Name</span>
|
|
|
+ </div>
|
|
|
+ <el-input placeholder="Please enter..." v-model="newFieldInfo.name"></el-input>
|
|
|
+ </div>
|
|
|
+ <div class="field-item field-value">
|
|
|
+ <div class="label">
|
|
|
+ <span class="required-symbol">*</span>
|
|
|
+ <span>Field Value</span>
|
|
|
+ </div>
|
|
|
+ <el-radio-group v-model="newFieldInfo.fieldType" @change="handleFieldTypeChange">
|
|
|
+ <el-radio label="Blank">Blank</el-radio>
|
|
|
+ <el-radio label="Fixed Value">Fixed Value</el-radio>
|
|
|
+ </el-radio-group>
|
|
|
+ </div>
|
|
|
+ <div class="field-item" v-if="newFieldInfo.fieldType === 'Fixed Value'">
|
|
|
+ <div class="label">
|
|
|
+ <span class="required-symbol">*</span>
|
|
|
+ <span>Fixed Value</span>
|
|
|
+ </div>
|
|
|
+ <el-input placeholder="Please enter..." v-model="newFieldInfo.value"></el-input>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <el-button
|
|
|
+ style="height: 40px; width: 115px"
|
|
|
+ class="cancel-btn"
|
|
|
+ type="default"
|
|
|
+ @click="addNewFieldVisible = false"
|
|
|
+ >Cancel</el-button
|
|
|
+ >
|
|
|
+ <el-button style="height: 40px; width: 120px" class="el-button--dark" @click="addNewField"
|
|
|
+ >Apply</el-button
|
|
|
+ >
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -258,6 +403,9 @@ watch(radioa, (newVal) => {
|
|
|
font-size: 18px;
|
|
|
font-weight: bold;
|
|
|
}
|
|
|
+ .right-option {
|
|
|
+ margin-left: auto;
|
|
|
+ }
|
|
|
.content-box {
|
|
|
height: 100%;
|
|
|
padding: 8px 16px 16px;
|
|
|
@@ -266,7 +414,7 @@ watch(radioa, (newVal) => {
|
|
|
.fields-configuration {
|
|
|
div.content-box {
|
|
|
display: flex;
|
|
|
- align-items: center;
|
|
|
+ align-items: flex-start;
|
|
|
justify-content: center;
|
|
|
min-height: 272px;
|
|
|
max-height: 400px;
|
|
|
@@ -275,6 +423,7 @@ watch(radioa, (newVal) => {
|
|
|
padding-right: 0px;
|
|
|
// overflow: auto;
|
|
|
.empty-box {
|
|
|
+ align-self: center;
|
|
|
width: 100%;
|
|
|
text-align: center;
|
|
|
p {
|
|
|
@@ -285,15 +434,23 @@ watch(radioa, (newVal) => {
|
|
|
.fields-list {
|
|
|
width: 100%;
|
|
|
max-height: 400px;
|
|
|
- padding-top: 8px;
|
|
|
+ padding: 8px 0;
|
|
|
padding-right: 16px;
|
|
|
overflow: auto;
|
|
|
+ user-select: none;
|
|
|
.field-item {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
+ height: 48px;
|
|
|
margin-bottom: 8px;
|
|
|
+ padding: 16px;
|
|
|
+ border-radius: 6px;
|
|
|
+ border: 1px solid var(--color-border);
|
|
|
.label {
|
|
|
flex: 1;
|
|
|
+ .required-symbol {
|
|
|
+ color: var(--color-danger);
|
|
|
+ }
|
|
|
}
|
|
|
.display-name {
|
|
|
flex: 1.3;
|
|
|
@@ -332,6 +489,21 @@ watch(radioa, (newVal) => {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ .ghost-column {
|
|
|
+ cursor: move !important;
|
|
|
+ span {
|
|
|
+ opacity: 0;
|
|
|
+ }
|
|
|
+ border: 1px dashed var(--color-customize-column-item-drag-border) !important;
|
|
|
+ background-color: var(--color-customize-column-item-drag-bg) !important;
|
|
|
+ box-shadow: none !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ .fallback-class {
|
|
|
+ opacity: 1 !important;
|
|
|
+ background-color: var(--color-customize-column-item-hover-bg) !important;
|
|
|
+ cursor: move !important;
|
|
|
+ }
|
|
|
}
|
|
|
.basic-info {
|
|
|
.info-item {
|
|
|
@@ -424,3 +596,37 @@ watch(radioa, (newVal) => {
|
|
|
}
|
|
|
}
|
|
|
</style>
|
|
|
+<style lang="scss">
|
|
|
+.add-new-field-dialog {
|
|
|
+ .field-item {
|
|
|
+ margin-bottom: 16px;
|
|
|
+ .label {
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .field-value {
|
|
|
+ .el-radio-group {
|
|
|
+ width: 100%;
|
|
|
+ .el-radio {
|
|
|
+ flex: 1;
|
|
|
+ margin-right: 0;
|
|
|
+ padding-left: 12px;
|
|
|
+ border: 1px solid var(--color-border);
|
|
|
+ &:first-child {
|
|
|
+ border-radius: 6px 0 0 6px;
|
|
|
+ border-right: none;
|
|
|
+ }
|
|
|
+ &:last-child {
|
|
|
+ border-radius: 0 6px 6px 0;
|
|
|
+ }
|
|
|
+ .el-radio__label {
|
|
|
+ color: var(--color-neutral-1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|