|
|
|
@ -1,101 +1,156 @@
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
import { computed, h, reactive, ref, unref } from "vue";
|
|
|
|
|
import { NDataTable, useDialog } from "naive-ui";
|
|
|
|
|
import type { DataTableColumns, DataTableRowKey } from "naive-ui";
|
|
|
|
|
import Action from "../comp/Action.vue";
|
|
|
|
|
import { RejectModal } from "./index";
|
|
|
|
|
import type { RowData } from "@/config/final";
|
|
|
|
|
import { getFinalList } from "@/api/final";
|
|
|
|
|
import type { ApprovalParam } from "/#/api";
|
|
|
|
|
import { audit } from "@/api/task/task";
|
|
|
|
|
import {
|
|
|
|
|
computed,
|
|
|
|
|
defineEmits,
|
|
|
|
|
h,
|
|
|
|
|
nextTick,
|
|
|
|
|
onBeforeMount,
|
|
|
|
|
onMounted,
|
|
|
|
|
onUnmounted,
|
|
|
|
|
reactive,
|
|
|
|
|
ref,
|
|
|
|
|
unref,
|
|
|
|
|
watch,
|
|
|
|
|
} from 'vue'
|
|
|
|
|
import { NDataTable, useDialog, useMessage } from 'naive-ui'
|
|
|
|
|
import type { DataTableColumns, DataTableRowKey } from 'naive-ui'
|
|
|
|
|
import {
|
|
|
|
|
ListAction,
|
|
|
|
|
StatusItem,
|
|
|
|
|
} from '../comp'
|
|
|
|
|
import { RejectModal } from './index'
|
|
|
|
|
import { useDictionary } from '@/store/modules/dictonary'
|
|
|
|
|
import type { RowData } from '@/config/final'
|
|
|
|
|
import { getFinalList, getRepeatList } from '@/api/final'
|
|
|
|
|
import { formatToDateHMS } from '@/utils/dateUtil'
|
|
|
|
|
import { audit } from '@/api/task/task'
|
|
|
|
|
import NotPassed from '@/components/Approval/NotPassed.vue'
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits<{
|
|
|
|
|
(e: "commit", columns: any[]);
|
|
|
|
|
}>();
|
|
|
|
|
|
|
|
|
|
const show = ref(false);
|
|
|
|
|
(e: 'commit', columns: any[])
|
|
|
|
|
}>()
|
|
|
|
|
const dicStore = useDictionary()
|
|
|
|
|
const message = useMessage()
|
|
|
|
|
const show = ref(false)
|
|
|
|
|
const izstatusList = ref([])
|
|
|
|
|
const dialog = useDialog()
|
|
|
|
|
const checkedRowKeys = ref([])
|
|
|
|
|
|
|
|
|
|
onBeforeMount(() => {
|
|
|
|
|
dicStore.fetchizstatusListt()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
function showModal() {
|
|
|
|
|
show.value = true;
|
|
|
|
|
show.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function closeModal() {
|
|
|
|
|
show.value = false;
|
|
|
|
|
show.value = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleSumbit(e: MouseEvent) {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
closeModal();
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
closeModal()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
showModal,
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const columns: DataTableColumns<RowData> = [
|
|
|
|
|
{
|
|
|
|
|
type: "selection",
|
|
|
|
|
fixed: "left",
|
|
|
|
|
type: 'selection',
|
|
|
|
|
fixed: 'left',
|
|
|
|
|
width: 50,
|
|
|
|
|
disabled(row: any) {
|
|
|
|
|
return row.states !== 2
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "任务Id",
|
|
|
|
|
key: "id",
|
|
|
|
|
fixed: "left",
|
|
|
|
|
width: 100,
|
|
|
|
|
title: '任务Id',
|
|
|
|
|
key: 'id',
|
|
|
|
|
fixed: 'left',
|
|
|
|
|
width: 180,
|
|
|
|
|
ellipsis: {
|
|
|
|
|
tooltip: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "任务名称",
|
|
|
|
|
key: "fromtaskname",
|
|
|
|
|
fixed: "left",
|
|
|
|
|
width: 200,
|
|
|
|
|
title: '任务名称',
|
|
|
|
|
key: 'fromtaskname',
|
|
|
|
|
fixed: 'left',
|
|
|
|
|
width: 150,
|
|
|
|
|
ellipsis: {
|
|
|
|
|
tooltip: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "审批节点",
|
|
|
|
|
key: "approvalnode",
|
|
|
|
|
title: '审批节点',
|
|
|
|
|
key: 'approvalnode',
|
|
|
|
|
width: 100,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "审批状态",
|
|
|
|
|
key: "states",
|
|
|
|
|
width: 100,
|
|
|
|
|
title: '审批状态',
|
|
|
|
|
key: 'states',
|
|
|
|
|
width: 120,
|
|
|
|
|
render(row) {
|
|
|
|
|
const item: any = izstatusList.value.find(
|
|
|
|
|
(item: any) => item.value == row.states,
|
|
|
|
|
)
|
|
|
|
|
return h(StatusItem, {
|
|
|
|
|
id: row.id,
|
|
|
|
|
status: row.states,
|
|
|
|
|
label: item ? item.label : '',
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "图片相似度",
|
|
|
|
|
key: "similarity",
|
|
|
|
|
title: '图片相似度',
|
|
|
|
|
key: 'similarityscore',
|
|
|
|
|
width: 100,
|
|
|
|
|
render(row: any) {
|
|
|
|
|
return h('div', {
|
|
|
|
|
id: row.id,
|
|
|
|
|
style: { color: row.similarityscore === 100 ? '#FF4E4F' : '' },
|
|
|
|
|
}, { default: () => row.similarityscore ? `${row.similarityscore}%` : '' })
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "提报时间",
|
|
|
|
|
key: "fromuptime",
|
|
|
|
|
title: '提报时间',
|
|
|
|
|
key: 'fromuptime',
|
|
|
|
|
width: 200,
|
|
|
|
|
render(row: any) {
|
|
|
|
|
return formatToDateHMS(row.createdate || 0)
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "更新时间",
|
|
|
|
|
key: "updatetime",
|
|
|
|
|
title: '更新时间',
|
|
|
|
|
key: 'updatetime',
|
|
|
|
|
width: 200,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "操作",
|
|
|
|
|
key: "actions",
|
|
|
|
|
title: '操作',
|
|
|
|
|
key: 'actions',
|
|
|
|
|
width: 200,
|
|
|
|
|
fixed: "right",
|
|
|
|
|
fixed: 'right',
|
|
|
|
|
render(row) {
|
|
|
|
|
return h(Action, {
|
|
|
|
|
return h(ListAction, {
|
|
|
|
|
id: row.id,
|
|
|
|
|
status: row.states,
|
|
|
|
|
trigger: actionHandler,
|
|
|
|
|
});
|
|
|
|
|
trigger: (action) => {
|
|
|
|
|
actionHandler(action, row)
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const rejectModalRef = ref(null);
|
|
|
|
|
const columnsRef = ref(columns);
|
|
|
|
|
const tableRef = ref<InstanceType<typeof NDataTable>>();
|
|
|
|
|
const rowKey = (row: RowData) => row.id;
|
|
|
|
|
const loading = ref(true);
|
|
|
|
|
const total = ref(0);
|
|
|
|
|
]
|
|
|
|
|
const notPassModalRef = ref(null) // 不通过弹窗
|
|
|
|
|
const rejectModalRef = ref(null)
|
|
|
|
|
const columnsRef = ref(columns)
|
|
|
|
|
const tableRef = ref<InstanceType<typeof NDataTable>>()
|
|
|
|
|
const rowKey = (row: RowData) => row.id
|
|
|
|
|
const loading = ref(true)
|
|
|
|
|
const total = ref(0)
|
|
|
|
|
const pagination = reactive({
|
|
|
|
|
page: 1,
|
|
|
|
|
pageCount: 1,
|
|
|
|
@ -103,136 +158,211 @@ const pagination = reactive({
|
|
|
|
|
showSizePicker: true,
|
|
|
|
|
pageSizes: [
|
|
|
|
|
{
|
|
|
|
|
label: "10 每页",
|
|
|
|
|
label: '10 每页',
|
|
|
|
|
value: 10,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "15 每页",
|
|
|
|
|
label: '15 每页',
|
|
|
|
|
value: 15,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "30 每页",
|
|
|
|
|
label: '30 每页',
|
|
|
|
|
value: 30,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
label: "50 每页",
|
|
|
|
|
label: '50 每页',
|
|
|
|
|
value: 50,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
showQuickJumper: true,
|
|
|
|
|
prefix:()=>`共 ${total.value} 条数据`
|
|
|
|
|
});
|
|
|
|
|
const tableData = ref<Array<RowData>>([]);
|
|
|
|
|
const selectionIds = ref<DataTableRowKey[]>([]);
|
|
|
|
|
prefix: () => `共 ${total.value} 条数据`,
|
|
|
|
|
})
|
|
|
|
|
const tableData = ref<Array<RowData>>([])
|
|
|
|
|
const selectionIds = ref<DataTableRowKey[]>([])
|
|
|
|
|
|
|
|
|
|
const deviceHeight = ref(600);
|
|
|
|
|
const deviceHeight = ref(500)
|
|
|
|
|
|
|
|
|
|
const maxHeight = computed(() => {
|
|
|
|
|
return tableData.value.length ? `${unref(deviceHeight)}px` : "auto";
|
|
|
|
|
});
|
|
|
|
|
return tableData.value.length ? `${unref(deviceHeight)}px` : 'auto'
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
async function query(page: number, pageSize: number) {
|
|
|
|
|
const result = await getFinalList({
|
|
|
|
|
sortorder: "asc",
|
|
|
|
|
pageSize: 10,
|
|
|
|
|
const result = await getRepeatList({
|
|
|
|
|
sortorder: 'asc',
|
|
|
|
|
pageSize: pagination.pageSize,
|
|
|
|
|
currPage: 1,
|
|
|
|
|
sortname: "",
|
|
|
|
|
});
|
|
|
|
|
const { data, pageCount,totalCount } = result;
|
|
|
|
|
total.value = totalCount;
|
|
|
|
|
tableData.value = data;
|
|
|
|
|
pagination.page = page;
|
|
|
|
|
pagination.pageCount = pageCount;
|
|
|
|
|
loading.value = false;
|
|
|
|
|
sortname: '',
|
|
|
|
|
})
|
|
|
|
|
console.log(666666)
|
|
|
|
|
console.log(result)
|
|
|
|
|
|
|
|
|
|
const { data, pageCount, totalCount } = result
|
|
|
|
|
total.value = totalCount
|
|
|
|
|
tableData.value = data
|
|
|
|
|
pagination.page = page
|
|
|
|
|
pagination.pageCount = pageCount
|
|
|
|
|
loading.value = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => dicStore.izstatusList,
|
|
|
|
|
(newval) => {
|
|
|
|
|
izstatusList.value = newval
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
async function handlePageChange(currentPage) {
|
|
|
|
|
if (loading.value) return;
|
|
|
|
|
pagination.page = currentPage;
|
|
|
|
|
const { pageSize } = pagination;
|
|
|
|
|
await query(currentPage, pageSize);
|
|
|
|
|
if (loading.value)
|
|
|
|
|
return
|
|
|
|
|
pagination.page = currentPage
|
|
|
|
|
const { pageSize } = pagination
|
|
|
|
|
await query(currentPage, pageSize)
|
|
|
|
|
}
|
|
|
|
|
async function handlePageSizeChange(currentPageSize) {
|
|
|
|
|
if (loading.value) return;
|
|
|
|
|
if (loading.value)
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
const { page } = pagination;
|
|
|
|
|
pagination.pageSize = currentPageSize;
|
|
|
|
|
const { page } = pagination
|
|
|
|
|
pagination.pageSize = currentPageSize
|
|
|
|
|
|
|
|
|
|
await query(page, currentPageSize);
|
|
|
|
|
await query(page, currentPageSize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleCheck(rowKeys: DataTableRowKey[]) {
|
|
|
|
|
selectionIds.value = rowKeys;
|
|
|
|
|
selectionIds.value = rowKeys
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function actionHandler(action: any) {
|
|
|
|
|
const { key } = action;
|
|
|
|
|
function validate(items: any[]) {
|
|
|
|
|
if (items.length === 0)
|
|
|
|
|
return '至少选中一个任务'
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function actionHandler(action: any, row: any) {
|
|
|
|
|
const { key } = action
|
|
|
|
|
switch (key) {
|
|
|
|
|
case "view":
|
|
|
|
|
break;
|
|
|
|
|
case "reset":
|
|
|
|
|
resetHandler();
|
|
|
|
|
break;
|
|
|
|
|
case "approval":
|
|
|
|
|
approvalHandler();
|
|
|
|
|
break;
|
|
|
|
|
case "reject":
|
|
|
|
|
(rejectModalRef.value as any).showModal();
|
|
|
|
|
break;
|
|
|
|
|
case 'view':
|
|
|
|
|
break
|
|
|
|
|
case 'reset':
|
|
|
|
|
// resetHandler()
|
|
|
|
|
break
|
|
|
|
|
case 'approval':
|
|
|
|
|
singleApproval(row)
|
|
|
|
|
break
|
|
|
|
|
case 'reject':
|
|
|
|
|
rejectHandler([row])
|
|
|
|
|
break
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const dialog = useDialog();
|
|
|
|
|
function getSelectItems() {
|
|
|
|
|
return tableData.value.filter(item => selectionIds.value.includes(item.id))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resetHandler() {
|
|
|
|
|
dialog.info({
|
|
|
|
|
title: "确认提示",
|
|
|
|
|
content: "确认重置当前选中的任务的审批吗?",
|
|
|
|
|
positiveText: "确定",
|
|
|
|
|
negativeText: "取消",
|
|
|
|
|
onPositiveClick: async () => {
|
|
|
|
|
// TODO:需要支持重置
|
|
|
|
|
// const result = await resetApproval()
|
|
|
|
|
},
|
|
|
|
|
onNegativeClick: () => {},
|
|
|
|
|
});
|
|
|
|
|
// 单个审批通过
|
|
|
|
|
function singleApproval(row) {
|
|
|
|
|
const param = {
|
|
|
|
|
result: true,
|
|
|
|
|
comment: '',
|
|
|
|
|
disposeType: '',
|
|
|
|
|
disposeTypeId: '',
|
|
|
|
|
failCauseId: '',
|
|
|
|
|
failCauseName: '',
|
|
|
|
|
flowTaskInfoList: [
|
|
|
|
|
{
|
|
|
|
|
formId: row.id,
|
|
|
|
|
taskId: row.taskId,
|
|
|
|
|
taskName: row.fromTaskName,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
}
|
|
|
|
|
doAudit(param)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function approvalHandler() {
|
|
|
|
|
// 批量通过
|
|
|
|
|
function batchApproval() {
|
|
|
|
|
const items: any = getSelectItems()
|
|
|
|
|
const msg = validate(items)
|
|
|
|
|
|
|
|
|
|
if (msg !== null) {
|
|
|
|
|
message.error(msg)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
console.log(items)
|
|
|
|
|
const list: any = []
|
|
|
|
|
items.forEach((item) => {
|
|
|
|
|
list.push({
|
|
|
|
|
formId: item.id,
|
|
|
|
|
taskId: item.taskId,
|
|
|
|
|
taskName: item.fromtaskname,
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const param = {
|
|
|
|
|
result: true,
|
|
|
|
|
comment: '',
|
|
|
|
|
disposeType: '',
|
|
|
|
|
disposeTypeId: '',
|
|
|
|
|
failCauseId: '',
|
|
|
|
|
failCauseName: '',
|
|
|
|
|
flowTaskInfoList: list,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
doAudit(param)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 批量不通过
|
|
|
|
|
function batchReject() {
|
|
|
|
|
const items: any = getSelectItems()
|
|
|
|
|
rejectHandler(items)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 审核通过
|
|
|
|
|
function doAudit(param: any) {
|
|
|
|
|
dialog.info({
|
|
|
|
|
title: "确认提示",
|
|
|
|
|
content: "确认给该任务审批为【通过】吗?",
|
|
|
|
|
positiveText: "确定",
|
|
|
|
|
negativeText: "取消",
|
|
|
|
|
title: '确认提示',
|
|
|
|
|
content: '确认给该任务审批为【通过】吗?',
|
|
|
|
|
positiveText: '确定',
|
|
|
|
|
negativeText: '取消',
|
|
|
|
|
onPositiveClick: () => {
|
|
|
|
|
// TODO:调用批量审批接口
|
|
|
|
|
audit(param).then((res) => {
|
|
|
|
|
const { code } = res
|
|
|
|
|
if (code === 'OK') {
|
|
|
|
|
message.success('审核成功')
|
|
|
|
|
reload()
|
|
|
|
|
}
|
|
|
|
|
else { message.error(res.message) }
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
onNegativeClick: () => {},
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function rejectHandler(idOrDesc: string, isOther: boolean) {
|
|
|
|
|
// TODO:实现批量拒绝
|
|
|
|
|
// const param: ApprovalParam = {
|
|
|
|
|
// formid: '',
|
|
|
|
|
// taskId: '',
|
|
|
|
|
// approvd: false,
|
|
|
|
|
// taskComment: '',
|
|
|
|
|
// }
|
|
|
|
|
// if (isOther)
|
|
|
|
|
// param.taskComment = idOrDesc
|
|
|
|
|
// else
|
|
|
|
|
// param.taskComment = idOrDesc
|
|
|
|
|
// audit(param)
|
|
|
|
|
// 审核不通过
|
|
|
|
|
function rejectHandler(list) {
|
|
|
|
|
const msg = validate(list)
|
|
|
|
|
if (msg !== null) {
|
|
|
|
|
message.error(msg)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const modal = unref(notPassModalRef)! as any
|
|
|
|
|
modal.showModal(list)
|
|
|
|
|
}
|
|
|
|
|
query(pagination.page, pagination.pageSize)
|
|
|
|
|
|
|
|
|
|
query(pagination.page, pagination.pageSize);
|
|
|
|
|
function reload() {
|
|
|
|
|
selectionIds.value = []
|
|
|
|
|
checkedRowKeys.value = []
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div>
|
|
|
|
|
<NotPassed ref="notPassModalRef" @success="reload" />
|
|
|
|
|
|
|
|
|
|
<n-modal v-model:show="show" transform-origin="center">
|
|
|
|
|
<n-card
|
|
|
|
|
class="cardstyle"
|
|
|
|
@ -248,9 +378,15 @@ query(pagination.page, pagination.pageSize);
|
|
|
|
|
<span :style="{ 'margin-left': '18px' }">任务信息</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="batch">
|
|
|
|
|
<img class="btn-approval btn-left" src="@/assets/images/task/btn-not-pass.png" alt="" @click.stop="batchReject">
|
|
|
|
|
<SvgIcon size="24" name="vs" />
|
|
|
|
|
<img class="btn-approval" src="@/assets/images/task/btn-pass.png" alt="" @click.stop="batchApproval">
|
|
|
|
|
</div>
|
|
|
|
|
<div class="wrapper-content">
|
|
|
|
|
<NDataTable
|
|
|
|
|
ref="tableRef"
|
|
|
|
|
v-model:checked-row-keys="checkedRowKeys"
|
|
|
|
|
remote
|
|
|
|
|
:columns="columnsRef"
|
|
|
|
|
:scroll-x="1250"
|
|
|
|
@ -267,7 +403,9 @@ query(pagination.page, pagination.pageSize);
|
|
|
|
|
</div>
|
|
|
|
|
<template #footer>
|
|
|
|
|
<div class="wrapper-footer">
|
|
|
|
|
<n-button type="info" @click="handleSumbit"> 确认 </n-button>
|
|
|
|
|
<n-button type="info" @click="handleSumbit">
|
|
|
|
|
确认
|
|
|
|
|
</n-button>
|
|
|
|
|
<n-button secondary style="margin-left: 15px" @click="closeModal">
|
|
|
|
|
取消
|
|
|
|
|
</n-button>
|
|
|
|
@ -280,6 +418,18 @@ query(pagination.page, pagination.pageSize);
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<style lang="less" scoped>
|
|
|
|
|
.batch {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin-top: 27px;
|
|
|
|
|
|
|
|
|
|
.btn-approval{
|
|
|
|
|
width: 68px;
|
|
|
|
|
height: 28px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
.wrapper {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|