mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-14 06:33:47 +08:00
2.0的js版本和后端 完成
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
<!--
|
||||
* 目录 表单 弹窗
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-modal :visible="visible" :title="form.categoryId ? '编辑' : '添加'" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
|
||||
<a-form-item label="分类名称" name="categoryName">
|
||||
<a-input v-model:value="form.categoryName" placeholder="请输入分类名称" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import _ from 'lodash';
|
||||
import { categoryApi } from '/@/api/business/category/category-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
// emit
|
||||
const emit = defineEmits('reloadList');
|
||||
|
||||
// 组件
|
||||
const formRef = ref();
|
||||
|
||||
// ------------------------------ 显示 、隐藏 ------------------------------
|
||||
|
||||
// 是否展示抽屉
|
||||
const visible = ref(false);
|
||||
|
||||
function showModal(categoryType, parentId, rowData) {
|
||||
Object.assign(form, formDefault);
|
||||
form.categoryType = categoryType;
|
||||
form.parentId = parentId;
|
||||
if (rowData && !_.isEmpty(rowData)) {
|
||||
Object.assign(form, rowData);
|
||||
}
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
Object.assign(form, formDefault);
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
// ------------------------------ 表单 ------------------------------
|
||||
|
||||
const formDefault = {
|
||||
categoryId: undefined,
|
||||
categoryName: '',
|
||||
categoryType: 1,
|
||||
parentId: undefined,
|
||||
disabledFlag: false,
|
||||
};
|
||||
let form = reactive({ ...formDefault });
|
||||
const rules = {
|
||||
categoryName: [{ required: true, message: '请输入分类名称' }],
|
||||
};
|
||||
|
||||
function onSubmit() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
if (form.categoryId) {
|
||||
await categoryApi.updateCategory(form);
|
||||
} else {
|
||||
await categoryApi.addCategory(form);
|
||||
}
|
||||
message.success(`${form.categoryId ? '修改' : '添加'}成功`);
|
||||
emit('reloadList', form.parentId);
|
||||
onClose();
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,163 @@
|
||||
<!--
|
||||
* 目录 表格
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-card size="small" :bordered="false" :hoverable="true">
|
||||
<a-row class="smart-table-btn-block">
|
||||
<div class="smart-table-operate-block">
|
||||
<a-button @click="addCategory()" type="primary" size="small" v-privilege="`${privilegePrefix}Category:add`">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新建
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="smart-table-setting-block"></div>
|
||||
</a-row>
|
||||
|
||||
<a-table
|
||||
:scroll="{ x: 1000 }"
|
||||
size="small"
|
||||
:dataSource="tableData"
|
||||
:columns="columns"
|
||||
rowKey="categoryId"
|
||||
bordered
|
||||
:pagination="false"
|
||||
@expandedRowsChange="changeExand"
|
||||
:expanded-row-keys="expandedRowKeys"
|
||||
>
|
||||
<template #bodyCell="{ record, column }">
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button @click="addCategory(record.categoryId)" type="link" v-privilege="`${privilegePrefix}Category:addChild`">增加子分类</a-button>
|
||||
<a-button @click="addCategory(undefined, record)" type="link" v-privilege="`${privilegePrefix}Category:edit`">编辑</a-button>
|
||||
<a-button @click="confirmDeleteCategory(record.categoryId)" danger type="link" v-privilege="`${privilegePrefix}Category:delete`">删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
<CategoryFormModal ref="formModal" @reloadList="reloadList" />
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted, computed } from 'vue';
|
||||
import { Modal, message } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import CategoryFormModal from './category-form-modal.vue';
|
||||
import { categoryApi } from '/@/api/business/category/category-api';
|
||||
import { CATEGORY_TYPE_ENUM } from '/@/constants/business/erp/category-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const columnNameList = [
|
||||
{
|
||||
categoryType: CATEGORY_TYPE_ENUM.GOODS.value,
|
||||
columnName: '商品分类',
|
||||
},
|
||||
{
|
||||
categoryType: CATEGORY_TYPE_ENUM.DEMO.value,
|
||||
columnName: '演示分类',
|
||||
},
|
||||
];
|
||||
const columName = computed(() => {
|
||||
let find = columnNameList.find((e) => e.categoryType == props.categoryType);
|
||||
return find ? find.columnName : '';
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
// 分组类型
|
||||
categoryType: Number,
|
||||
privilegePrefix: {
|
||||
type: String,
|
||||
default: 'goods'
|
||||
}
|
||||
});
|
||||
|
||||
// ------------------------------ 查询 ------------------------------
|
||||
const tableLoading = ref(false);
|
||||
const tableData = ref([]);
|
||||
const columns = reactive([
|
||||
{
|
||||
title: columName,
|
||||
dataIndex: 'categoryName',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
width: 200,
|
||||
},
|
||||
]);
|
||||
|
||||
async function queryList() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
let queryForm = {
|
||||
categoryType: props.categoryType,
|
||||
};
|
||||
let responseModel = await categoryApi.queryCategoryTree(queryForm);
|
||||
const list = responseModel.data;
|
||||
tableData.value = list;
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
const expandedRowKeys = ref([]);
|
||||
function reloadList(parentId) {
|
||||
queryList();
|
||||
if (parentId) {
|
||||
expandedRowKeys.value.push(parentId);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(queryList);
|
||||
defineExpose({
|
||||
queryList,
|
||||
});
|
||||
|
||||
function changeExand(val) {
|
||||
expandedRowKeys.value = val;
|
||||
}
|
||||
|
||||
// ------------------------------ 添加 ------------------------------
|
||||
|
||||
const formModal = ref();
|
||||
function addCategory(parentId, rowData) {
|
||||
formModal.value.showModal(props.categoryType, parentId, rowData);
|
||||
}
|
||||
|
||||
// ------------------------------ 删除 ------------------------------
|
||||
|
||||
function confirmDeleteCategory(categoryId) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除当前分类吗?',
|
||||
okText: '确定',
|
||||
okType: 'danger',
|
||||
async onOk() {
|
||||
deleteCategory(categoryId);
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
async function deleteCategory(categoryId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
await categoryApi.deleteCategoryById(categoryId);
|
||||
message.success('撤销成功');
|
||||
queryList();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
* 目录 demo
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<CategoryTreeTable :category-type="CATEGORY_TYPE_ENUM.DEMO.value" :privilegePrefix="'custom'"/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import CategoryTreeTable from './components/category-tree-table.vue';
|
||||
import { CATEGORY_TYPE_ENUM } from '/@/constants/business/erp/category-const';
|
||||
</script>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
* 目录 商品
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<CategoryTreeTable :category-type="CATEGORY_TYPE_ENUM.GOODS.value" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import CategoryTreeTable from './components/category-tree-table.vue';
|
||||
import { CATEGORY_TYPE_ENUM } from '/@/constants/business/erp/category-const';
|
||||
</script>
|
||||
@@ -0,0 +1,150 @@
|
||||
<!--
|
||||
* 商品表单
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-drawer :title="form.goodsId ? '编辑' : '添加'" :width="500" :visible="visible" :body-style="{ paddingBottom: '80px' }" @close="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }">
|
||||
<a-form-item label="商品分类" name="categoryId">
|
||||
<CategoryTree v-model:value="form.categoryId" placeholder="请选择商品分类" :categoryType="CATEGORY_TYPE_ENUM.GOODS.value" />
|
||||
</a-form-item>
|
||||
<a-form-item label="商品名称" name="goodsName">
|
||||
<a-input v-model:value="form.goodsName" placeholder="请输入商品名称" />
|
||||
</a-form-item>
|
||||
<a-form-item label="商品状态" name="goodsStatus">
|
||||
<SmartEnumSelect enum-name="GOODS_STATUS_ENUM" v-model:value="form.goodsStatus" />
|
||||
</a-form-item>
|
||||
<a-form-item label="产地" name="place">
|
||||
<DictSelect key-code="GODOS_PLACE" v-model:value="form.place" />
|
||||
</a-form-item>
|
||||
<a-form-item label="上架状态" name="shelvesFlag">
|
||||
<a-radio-group v-model:value="form.shelvesFlag">
|
||||
<a-radio :value="true">上架</a-radio>
|
||||
<a-radio :value="false">下架</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="商品价格" name="price">
|
||||
<a-input-number style="width: 100%" placeholder="请输入商品价格" v-model:value="form.price" :min="0" />
|
||||
</a-form-item>
|
||||
<a-form-item label="备注" name="remark">
|
||||
<a-input style="width: 100%" placeholder="请输入备注" v-model:value="form.remark" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<div
|
||||
:style="{
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
width: '100%',
|
||||
borderTop: '1px solid #e9e9e9',
|
||||
padding: '10px 16px',
|
||||
background: '#fff',
|
||||
textAlign: 'right',
|
||||
zIndex: 1,
|
||||
}"
|
||||
>
|
||||
<a-button style="margin-right: 8px" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" @click="onSubmit">提交</a-button>
|
||||
</div>
|
||||
</a-drawer>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, nextTick, reactive } from 'vue';
|
||||
import CategoryTree from '/@/components/business/category-tree-select/index.vue';
|
||||
import { CATEGORY_TYPE_ENUM } from '/@/constants/business/erp/category-const';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { GOODS_STATUS_ENUM } from '/@/constants/business/erp/goods-const';
|
||||
import _ from 'lodash';
|
||||
import { goodsApi } from '/@/api/business/goods/goods-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
|
||||
import DictSelect from '/@/components/support/dict-select/index.vue';
|
||||
|
||||
// emit
|
||||
const emit = defineEmits('reloadList');
|
||||
|
||||
// 组件ref
|
||||
const formRef = ref();
|
||||
|
||||
const formDefault = {
|
||||
//商品分类
|
||||
categoryId: undefined,
|
||||
//商品名称
|
||||
goodsName: undefined,
|
||||
//商品状态
|
||||
goodsStatus: GOODS_STATUS_ENUM.APPOINTMENT.value,
|
||||
//产地
|
||||
place: undefined,
|
||||
//商品价格
|
||||
price: undefined,
|
||||
//上架状态
|
||||
shelvesFlag: true,
|
||||
//备注
|
||||
remark: '',
|
||||
//商品id
|
||||
goodsId: undefined,
|
||||
};
|
||||
let form = reactive({ ...formDefault });
|
||||
const rules = {
|
||||
categoryId: [{ required: true, message: '请选择商品分类' }],
|
||||
goodsName: [{ required: true, message: '商品名称不能为空' }],
|
||||
goodsStatus: [{ required: true, message: '商品状态不能为空' }],
|
||||
price: [{ required: true, message: '商品价格不能为空' }],
|
||||
place: [{ required: true, message: '产地不能为空' }],
|
||||
};
|
||||
// 是否展示抽屉
|
||||
const visible = ref(false);
|
||||
|
||||
function showDrawer(rowData) {
|
||||
Object.assign(form, formDefault);
|
||||
if (rowData && !_.isEmpty(rowData)) {
|
||||
Object.assign(form, rowData);
|
||||
}
|
||||
console.log(form);
|
||||
visible.value = true;
|
||||
nextTick(() => {
|
||||
formRef.value.clearValidate();
|
||||
});
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
Object.assign(form, formDefault);
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
if (form.goodsId) {
|
||||
await goodsApi.updateGoods(form);
|
||||
} else {
|
||||
await goodsApi.addGoods(form);
|
||||
}
|
||||
message.success(`${form.goodsId ? '修改' : '添加'}成功`);
|
||||
onClose();
|
||||
emit('reloadList');
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showDrawer,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,309 @@
|
||||
<!--
|
||||
* 商品列表
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-07-21 21:55:12
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<!---------- 查询表单form begin ----------->
|
||||
<a-form class="smart-query-form">
|
||||
<a-row class="smart-query-form-row" v-privilege="'goods:query'">
|
||||
<a-form-item label="商品分类" class="smart-query-form-item">
|
||||
<category-tree
|
||||
width="150px"
|
||||
v-model:value="queryForm.categoryId"
|
||||
placeholder="请选择商品分类"
|
||||
:categoryType="CATEGORY_TYPE_ENUM.GOODS.value"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="商品名称" class="smart-query-form-item">
|
||||
<a-input style="width: 200px" v-model:value="queryForm.searchWord" placeholder="商品名称" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="产地" name="place" class="smart-query-form-item">
|
||||
<DictSelect key-code="GODOS_PLACE" v-model:value="queryForm.place" width="120px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="商品状态" name="goodsStatus" class="smart-query-form-item">
|
||||
<SmartEnumSelect enum-name="GOODS_STATUS_ENUM" v-model:value="queryForm.goodsStatus" width="160px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="快速筛选" class="smart-query-form-item">
|
||||
<a-radio-group v-model:value="queryForm.shelvesFlag" @change="queryData">
|
||||
<a-radio-button :value="undefined">全部</a-radio-button>
|
||||
<a-radio-button :value="true">上架</a-radio-button>
|
||||
<a-radio-button :value="false">下架</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="smart-query-form-item">
|
||||
<a-button type="primary" @click="queryData" v-privilege="'goods:query'">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="resetQuery" class="smart-margin-left10" v-privilege="'goods:query'">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<!---------- 查询表单form end ----------->
|
||||
|
||||
<a-card size="small" :bordered="false" :hoverable="true">
|
||||
<!---------- 表格操作行 begin ----------->
|
||||
<a-row class="smart-table-btn-block">
|
||||
<div class="smart-table-operate-block">
|
||||
<a-button @click="addGoods" type="primary" size="small" v-privilege="'goods:add'">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新建
|
||||
</a-button>
|
||||
|
||||
<a-button @click="confirmBatchDelete" type="danger" size="small" :disabled="selectedRowKeyList.length == 0" v-privilege="'goods:batchDelete'">
|
||||
<template #icon>
|
||||
<DeleteOutlined />
|
||||
</template>
|
||||
批量删除
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="smart-table-setting-block">
|
||||
<TableOperator v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.ERP.GOODS" :refresh="queryData" />
|
||||
</div>
|
||||
</a-row>
|
||||
<!---------- 表格操作行 end ----------->
|
||||
|
||||
<a-table
|
||||
size="small"
|
||||
:dataSource="tableData"
|
||||
:columns="columns"
|
||||
rowKey="goodsId"
|
||||
bordered
|
||||
:pagination="false"
|
||||
:row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
|
||||
>
|
||||
<template #bodyCell="{ text, record, column }">
|
||||
<template v-if="column.dataIndex === 'place'">
|
||||
<span>{{ text && text.length > 0 ? text[0].valueName : '' }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'goodsStatus'">
|
||||
<span>{{ $smartEnumPlugin.getDescByValue('GOODS_STATUS_ENUM', text) }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'shelvesFlag'">
|
||||
<span>{{ text ? '上架' : '下架' }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button @click="addGoods(record)" type="link" v-privilege="'goods:update'">编辑</a-button>
|
||||
<a-button @click="deleteGoods(record)" danger type="link" v-privilege="'goods:delete'">删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryData"
|
||||
@showSizeChange="queryData"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<GoodsFormModal ref="formModal" @reloadList="queryData" />
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import GoodsFormModal from './components/goods-form-modal.vue';
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { goodsApi } from '/@/api/business/goods/goods-api';
|
||||
import { PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import CategoryTree from '/@/components/business/category-tree-select/index.vue';
|
||||
import { CATEGORY_TYPE_ENUM } from '/@/constants/business/erp/category-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||||
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||||
import { GOODS_STATUS_ENUM } from '/@/constants/business/erp/goods-const';
|
||||
import DictSelect from '/@/components/support/dict-select/index.vue';
|
||||
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
|
||||
|
||||
// ---------------------------- 表格列 ----------------------------
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '商品分类',
|
||||
dataIndex: 'categoryName',
|
||||
},
|
||||
{
|
||||
title: '商品名称',
|
||||
dataIndex: 'goodsName',
|
||||
},
|
||||
{
|
||||
title: '商品状态',
|
||||
dataIndex: 'goodsStatus',
|
||||
},
|
||||
{
|
||||
title: '产地',
|
||||
dataIndex: 'place',
|
||||
},
|
||||
{
|
||||
title: '商品价格',
|
||||
dataIndex: 'price',
|
||||
},
|
||||
{
|
||||
title: '上架状态',
|
||||
dataIndex: 'shelvesFlag',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
dataIndex: 'remark',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 100,
|
||||
},
|
||||
]);
|
||||
|
||||
// ---------------------------- 查询数据表单和方法 ----------------------------
|
||||
|
||||
const queryFormState = {
|
||||
categoryId: undefined,
|
||||
searchWord: '',
|
||||
goodsStatus: undefined,
|
||||
place: undefined,
|
||||
shelvesFlag: undefined,
|
||||
goodsType: undefined,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
// 查询表单form
|
||||
const queryForm = reactive({ ...queryFormState });
|
||||
// 表格加载loading
|
||||
const tableLoading = ref(false);
|
||||
// 表格数据
|
||||
const tableData = ref([]);
|
||||
// 总数
|
||||
const total = ref(0);
|
||||
|
||||
// 重置查询条件
|
||||
function resetQuery() {
|
||||
let pageSize = queryForm.pageSize;
|
||||
Object.assign(queryForm, queryFormState);
|
||||
queryForm.pageSize = pageSize;
|
||||
queryData();
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
async function queryData() {
|
||||
tableLoading.value = true;
|
||||
try {
|
||||
let queryResult = await goodsApi.queryGoodsList(queryForm);
|
||||
|
||||
tableData.value = queryResult.data.list;
|
||||
total.value = queryResult.data.total;
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(queryData);
|
||||
|
||||
// ---------------------------- 添加/修改 ----------------------------
|
||||
const formModal = ref();
|
||||
|
||||
function addGoods(goodsData) {
|
||||
formModal.value.showDrawer(goodsData);
|
||||
}
|
||||
// ---------------------------- 单个删除 ----------------------------
|
||||
|
||||
function deleteGoods(goodsData) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除【' + goodsData.goodsName + '】吗?',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
onOk() {
|
||||
singleDelete(goodsData);
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
async function singleDelete(goodsData) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
await goodsApi.deleteGoods(goodsData.goodsId);
|
||||
message.success('删除成功');
|
||||
queryData();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------- 批量删除 ----------------------------
|
||||
|
||||
// 选择表格行
|
||||
const selectedRowKeyList = ref([]);
|
||||
|
||||
function onSelectChange(selectedRowKeys) {
|
||||
selectedRowKeyList.value = selectedRowKeys;
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
function confirmBatchDelete() {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除选中商品吗?',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
onOk() {
|
||||
batchDelete();
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
async function batchDelete() {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
await goodsApi.batchDelete(selectedRowKeyList.value);
|
||||
message.success('删除成功');
|
||||
queryData();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,239 @@
|
||||
<!--
|
||||
* 企业 银行列表
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-15 20:15:49
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-form class="smart-query-form">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 300px" v-model:value="queryForm.keywords" placeholder="开户银行/账户名称/账户/创建人" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="创建时间" class="smart-query-form-item">
|
||||
<a-space direction="vertical" :size="12">
|
||||
<a-range-picker v-model:value="searchDate" @change="dateChange" />
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button type="primary" @click="ajaxQuery">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="resetQuery">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
|
||||
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新建账户
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false" :hoverable="false">
|
||||
<a-row justify="end">
|
||||
<TableOperator class="smart-margin-bottom5" v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE_BANK" :refresh="ajaxQuery" />
|
||||
</a-row>
|
||||
<a-table :scroll="{ x: 1300 }" size="small" :dataSource="tableData" bordered :columns="columns" rowKey="bankId" :pagination="false">
|
||||
<template #bodyCell="{ record, column }">
|
||||
<template v-if="column.dataIndex === 'disabledFlag'">
|
||||
{{ record.disabledFlag ? '禁用' : '启用' }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'businessFlag'">
|
||||
{{ record.businessFlag ? '是' : '否' }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button @click="addOrUpdate(record)" type="link">编辑</a-button>
|
||||
<a-button @click="confirmDelete(record.bankId)" danger type="link">删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
<!--新建编辑modal-->
|
||||
<BankOperateModal ref="operateModal" :enterpriseId="enterpriseId" @reloadList="ajaxQuery" />
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { bankApi } from '/@/api/business/oa/bank-api';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import BankOperateModal from './enterprise-bank-operate-modal.vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||||
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||||
|
||||
const props = defineProps({
|
||||
enterpriseId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '开户银行',
|
||||
dataIndex: 'bankName',
|
||||
},
|
||||
{
|
||||
title: '账户名称',
|
||||
dataIndex: 'accountName',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '账号',
|
||||
width: 100,
|
||||
dataIndex: 'accountNumber',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '是否对公',
|
||||
width: 120,
|
||||
dataIndex: 'businessFlag',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
width: 80,
|
||||
dataIndex: 'disabledFlag',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
width: 100,
|
||||
dataIndex: 'remark',
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
width: 100,
|
||||
dataIndex: 'createUserName',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 100,
|
||||
},
|
||||
]);
|
||||
|
||||
const queryFormState = {
|
||||
enterpriseId: props.enterpriseId,
|
||||
keywords: '',
|
||||
endTime: null,
|
||||
startTime: null,
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
searchCount: true,
|
||||
};
|
||||
const queryForm = reactive({ ...queryFormState });
|
||||
const tableLoading = ref(false);
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
const operateModal = ref();
|
||||
|
||||
// 日期选择
|
||||
let searchDate = ref();
|
||||
|
||||
function dateChange(dates, dateStrings) {
|
||||
queryForm.startTime = dateStrings[0];
|
||||
queryForm.endTime = dateStrings[1];
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
searchDate.value = [];
|
||||
Object.assign(queryForm, queryFormState, { enterpriseId: props.enterpriseId });
|
||||
ajaxQuery();
|
||||
}
|
||||
|
||||
async function ajaxQuery() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
let responseModel = await bankApi.pageQuery(queryForm);
|
||||
const list = responseModel.data.list;
|
||||
total.value = responseModel.data.total;
|
||||
tableData.value = list;
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function confirmDelete(bankId) {
|
||||
Modal.confirm({
|
||||
title: '确定要删除吗?',
|
||||
content: '删除后,该信息将不可恢复',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
onOk() {
|
||||
del(bankId);
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
async function del(bankId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
await bankApi.delete(bankId);
|
||||
message.success('删除成功');
|
||||
ajaxQuery();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function addOrUpdate(rowData) {
|
||||
operateModal.value.showModal(rowData);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.enterpriseId,
|
||||
(value) => {
|
||||
if (value) {
|
||||
queryForm.enterpriseId = value;
|
||||
ajaxQuery();
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,133 @@
|
||||
<!--
|
||||
* 企业 银行 表单
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-15 20:15:49
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-modal :visible="visible" :title="form.bankId ? '编辑' : '添加'" ok-text="确认" cancel-text="取消" @ok="onSubmit"
|
||||
@cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-item label="开户银行" name="bankName">
|
||||
<a-input v-model:value="form.bankName" placeholder="请输入开户银行"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="账户名称" name="accountName">
|
||||
<a-input v-model:value="form.accountName" placeholder="请输入账户名称"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="账号" name="accountNumber">
|
||||
<a-input v-model:value="form.accountNumber" placeholder="请输入账号"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="是否对公" name="businessFlag">
|
||||
<a-switch v-model:checked="businessFlagChecked" @change="businessFlagCheckedChange"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="启用状态" name="disabledFlag">
|
||||
<a-switch v-model:checked="enabledChecked" @change="enabledCheckedChange"/>
|
||||
</a-form-item>
|
||||
<a-form-item label="备注" name="remark">
|
||||
<a-textarea v-model:value="form.remark" :rows="2"/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup>
|
||||
import {ref, reactive} from 'vue';
|
||||
import {message} from 'ant-design-vue';
|
||||
import { SmartLoading } from "/@/components/framework/smart-loading";
|
||||
import {bankApi} from '/@/api/business/oa/bank-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const props = defineProps({
|
||||
enterpriseId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
}
|
||||
});
|
||||
// emit
|
||||
const emit = defineEmits(['reloadList']);
|
||||
|
||||
// ---------------------- 显示、隐藏 ----------------------
|
||||
// 是否展示
|
||||
const visible = ref(false);
|
||||
function showModal(rowData) {
|
||||
Object.assign(form, formDefault);
|
||||
if (rowData) {
|
||||
Object.assign(form, rowData);
|
||||
businessFlagChecked.value = rowData.businessFlag;
|
||||
enabledChecked.value = !rowData.disabledFlag;
|
||||
}
|
||||
form.enterpriseId = props.enterpriseId;
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
Object.assign(form, formDefault);
|
||||
formRef.value.resetFields();
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
// ---------------------- 表单 ----------------------
|
||||
|
||||
// 组件
|
||||
const formRef = ref();
|
||||
|
||||
const formDefault = {
|
||||
bankId: undefined,
|
||||
enterpriseId: undefined,
|
||||
bankName: '',
|
||||
accountName: '',
|
||||
accountNumber: '',
|
||||
businessFlag: false,
|
||||
disabledFlag: false,
|
||||
remark: '',
|
||||
};
|
||||
let form = reactive({...formDefault});
|
||||
const rules = {
|
||||
bankName: [{required: true, message: '请输入开户银行'}],
|
||||
accountName: [{required: true, message: '请输入账户名称'}],
|
||||
accountNumber: [{required: true, message: '请输入账号'}],
|
||||
};
|
||||
|
||||
const businessFlagChecked = ref(false);
|
||||
const enabledChecked = ref(true);
|
||||
|
||||
function businessFlagCheckedChange(checked) {
|
||||
form.businessFlag = checked;
|
||||
}
|
||||
function enabledCheckedChange(checked) {
|
||||
form.disabledFlag = !checked;
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
if (form.bankId) {
|
||||
await bankApi.update(form);
|
||||
} else {
|
||||
await bankApi.create(form);
|
||||
}
|
||||
message.success(`${form.bankId ? '修改' : '添加'}成功`);
|
||||
emit('reloadList');
|
||||
onClose();
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
debugger
|
||||
console.log('error', error);
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,275 @@
|
||||
<!--
|
||||
* 企业 员工
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-15 20:15:49
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<div class="header">
|
||||
<div>
|
||||
关键字:
|
||||
<a-input style="width: 250px" v-model:value="queryForm.keywords" placeholder="姓名/手机号/登录账号" />
|
||||
<a-button class="button-style" type="primary" @click="queryEmployee">搜索</a-button>
|
||||
<a-button class="button-style" type="default" @click="resetQueryEmployee">重置</a-button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a-button class="button-style" type="primary" @click="addEmployee" v-privilege="'enterprise:addEmployee'"> 添加员工 </a-button>
|
||||
<a-button class="button-style" type="primary" danger @click="batchDelete" v-privilege="'enterprise:deleteEmployee'"> 批量移除 </a-button>
|
||||
</div>
|
||||
</div>
|
||||
<a-table
|
||||
:loading="tableLoading"
|
||||
:dataSource="tableData"
|
||||
:columns="columns"
|
||||
:pagination="false"
|
||||
rowKey="employeeId"
|
||||
:row-selection="{ selectedRowKeys: selectedRowKeyList, onChange: onSelectChange }"
|
||||
size="small"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ text, record, index, column }">
|
||||
<template v-if="column.dataIndex === 'disabledFlag'">
|
||||
<a-tag :color="text ? 'error' : 'processing'">{{ text ? '禁用' : '启用' }}</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'gender'">
|
||||
<span>{{ $smartEnumPlugin.getDescByValue('GENDER_ENUM', text) }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'operate'">
|
||||
<a @click="deleteEmployee(record.employeeId)" v-privilege="'enterprise:deleteEmployee'">移除</a>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryEmployee"
|
||||
@showSizeChange="queryEmployee"
|
||||
:show-total="showTableTotal"
|
||||
/>
|
||||
</div>
|
||||
<EmployeeTableSelectModal ref="selectEmployeeModal" @selectData="selectData" />
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import EmployeeTableSelectModal from '/@/components/system/employee-table-select-modal/index.vue';
|
||||
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { computed, reactive, ref, watch } from 'vue';
|
||||
import { enterpriseApi } from '/@/api/business/oa/enterprise-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS, showTableTotal } from '/@/constants/common-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const props = defineProps({
|
||||
enterpriseId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const columns = reactive([
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'actualName',
|
||||
},
|
||||
{
|
||||
title: '手机号',
|
||||
dataIndex: 'phone',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '登录账号',
|
||||
dataIndex: 'loginName',
|
||||
},
|
||||
{
|
||||
title: '企业',
|
||||
dataIndex: 'enterpriseName',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '部门',
|
||||
dataIndex: 'departmentName',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'disabledFlag',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operate',
|
||||
width: 60,
|
||||
},
|
||||
]);
|
||||
|
||||
// --------------------------- 查询 ---------------------------
|
||||
|
||||
const defaultQueryForm = {
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
enterpriseId: undefined,
|
||||
keywords: undefined,
|
||||
};
|
||||
// 查询表单
|
||||
const queryForm = reactive({ ...defaultQueryForm });
|
||||
const total = ref(0);
|
||||
const tableData = ref([]);
|
||||
const tableLoading = ref(false);
|
||||
|
||||
function resetQueryEmployee() {
|
||||
queryForm.keywords = '';
|
||||
queryEmployee();
|
||||
}
|
||||
|
||||
async function queryEmployee() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
queryForm.enterpriseId = props.enterpriseId;
|
||||
let res = await enterpriseApi.queryPageEmployeeList(queryForm);
|
||||
tableData.value = res.data.list;
|
||||
total.value = res.data.total;
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function selectData(list) {
|
||||
if (_.isEmpty(list)) {
|
||||
message.warning('请选择员工');
|
||||
return;
|
||||
}
|
||||
SmartLoading.show();
|
||||
try {
|
||||
let params = {
|
||||
employeeIdList: list,
|
||||
enterpriseId: props.enterpriseId,
|
||||
};
|
||||
await enterpriseApi.addEmployee(params);
|
||||
message.success('添加成功');
|
||||
await queryEmployee();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------- 添加员工 ---------------------------
|
||||
|
||||
// 添加员工
|
||||
const selectEmployeeModal = ref();
|
||||
async function addEmployee() {
|
||||
let res = await enterpriseApi.employeeList([props.enterpriseId]);
|
||||
let selectedIdList = res.data.map((e) => e.employeeId) || [];
|
||||
selectEmployeeModal.value.showModal(selectedIdList);
|
||||
}
|
||||
|
||||
// --------------------------- 删除 ---------------------------
|
||||
|
||||
// 删除员工方法
|
||||
async function deleteEmployee(employeeId) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除该企业下的员工么?',
|
||||
okText: '确定',
|
||||
okType: 'danger',
|
||||
async onOk() {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
let param = {
|
||||
employeeIdList: [employeeId],
|
||||
enterpriseId: props.enterpriseId,
|
||||
};
|
||||
await enterpriseApi.deleteEmployee(param);
|
||||
message.success('移除成功');
|
||||
await queryEmployee();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
// 批量删除
|
||||
const selectedRowKeyList = ref([]);
|
||||
const hasSelected = computed(() => selectedRowKeyList.value.length > 0);
|
||||
function onSelectChange(selectedRowKeys) {
|
||||
selectedRowKeyList.value = selectedRowKeys;
|
||||
}
|
||||
|
||||
// 批量移除
|
||||
function batchDelete() {
|
||||
if (!hasSelected.value) {
|
||||
message.warning('请选择要删除的员工');
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定要删除该企业下的员工么?',
|
||||
okText: '确定',
|
||||
okType: 'danger',
|
||||
async onOk() {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
let params = {
|
||||
employeeIdList: selectedRowKeyList.value,
|
||||
enterpriseId: props.enterpriseId,
|
||||
};
|
||||
await enterpriseApi.deleteEmployee(params);
|
||||
message.success('移除成功');
|
||||
selectedRowKeyList.value = [];
|
||||
await queryEmployee();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.enterpriseId,
|
||||
(e) => {
|
||||
if (e) {
|
||||
queryEmployee();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.button-style {
|
||||
margin: 0 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,243 @@
|
||||
<!--
|
||||
* 企业 发票信息
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-15 20:15:49
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-form class="smart-query-form">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 300px" v-model:value="queryForm.keywords" placeholder="开票抬头/银行账户/创建人" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="创建时间" class="smart-query-form-item">
|
||||
<a-space direction="vertical" :size="12">
|
||||
<a-range-picker v-model:value="searchDate" @change="dateChange" />
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button type="primary" @click="ajaxQuery">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="resetQuery">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
|
||||
<a-button @click="addOrUpdate()" type="primary" class="smart-margin-left20">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新建发票
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false" :hoverable="false">
|
||||
<a-row justify="end">
|
||||
<TableOperator class="smart-margin-bottom5" v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE_INVOICE" :refresh="ajaxQuery" />
|
||||
</a-row>
|
||||
<a-table :scroll="{ x: 1300 }" size="small" :dataSource="tableData" :columns="columns" rowKey="invoiceId" :pagination="false" bordered>
|
||||
<template #bodyCell="{ text, record, index, column }">
|
||||
<template v-if="column.dataIndex === 'disabledFlag'">
|
||||
{{ record.disabledFlag ? '禁用' : '启用' }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button @click="addOrUpdate(record)" type="link">编辑</a-button>
|
||||
<a-button @click="confirmDelete(record.invoiceId)" type="link" danger>删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
<!--新建编辑modal-->
|
||||
<InvoiceOperateModal ref="operateModal" :enterpriseId="enterpriseId" @reloadList="ajaxQuery" />
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import { invoiceApi } from '/@/api/business/oa/invoice-api';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import InvoiceOperateModal from './enterprise-invoice-operate-modal.vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||||
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||||
|
||||
const props = defineProps({
|
||||
enterpriseId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: 'ID',
|
||||
width: 50,
|
||||
dataIndex: 'invoiceId',
|
||||
},
|
||||
{
|
||||
title: '开票抬头',
|
||||
dataIndex: 'invoiceHeads',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '纳税人识别号',
|
||||
dataIndex: 'taxpayerIdentificationNumber',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '银行账号',
|
||||
width: 100,
|
||||
dataIndex: 'accountNumber',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '开户行',
|
||||
width: 120,
|
||||
dataIndex: 'bankName',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
width: 80,
|
||||
dataIndex: 'disabledFlag',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
width: 100,
|
||||
dataIndex: 'remark',
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
width: 100,
|
||||
dataIndex: 'createUserName',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 100,
|
||||
},
|
||||
]);
|
||||
|
||||
const queryFormState = {
|
||||
enterpriseId: props.enterpriseId,
|
||||
keywords: '',
|
||||
endTime: null,
|
||||
startTime: null,
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
searchCount: true,
|
||||
};
|
||||
const queryForm = reactive({ ...queryFormState });
|
||||
const tableLoading = ref(false);
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
const operateModal = ref();
|
||||
|
||||
// 日期选择
|
||||
let searchDate = ref();
|
||||
|
||||
function dateChange(dates, dateStrings) {
|
||||
queryForm.startTime = dateStrings[0];
|
||||
queryForm.endTime = dateStrings[1];
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
searchDate.value = [];
|
||||
Object.assign(queryForm, queryFormState);
|
||||
ajaxQuery();
|
||||
}
|
||||
|
||||
async function ajaxQuery() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
let responseModel = await invoiceApi.pageQuery(queryForm);
|
||||
const list = responseModel.data.list;
|
||||
total.value = responseModel.data.total;
|
||||
tableData.value = list;
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function confirmDelete(invoiceId) {
|
||||
Modal.confirm({
|
||||
title: '确定要删除吗?',
|
||||
content: '删除后,该信息将不可恢复',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
onOk() {
|
||||
del(invoiceId);
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
async function del(invoiceId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
await invoiceApi.delete(invoiceId);
|
||||
message.success('删除成功');
|
||||
ajaxQuery();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function addOrUpdate(rowData) {
|
||||
operateModal.value.showModal(rowData);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.enterpriseId,
|
||||
(value) => {
|
||||
if (value) {
|
||||
queryForm.enterpriseId = value;
|
||||
ajaxQuery();
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
@@ -0,0 +1,127 @@
|
||||
<!--
|
||||
* 企业 发票 表单
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-15 20:15:49
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-modal :visible="visible" :title="form.invoiceId ? '编辑' : '添加'" ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 5 }" :wrapper-col="{ span: 12 }">
|
||||
<a-form-item label="开票抬头" name="invoiceHeads">
|
||||
<a-input v-model:value="form.invoiceHeads" placeholder="请输入开票抬头" />
|
||||
</a-form-item>
|
||||
<a-form-item label="纳税人识别号" name="taxpayerIdentificationNumber">
|
||||
<a-input v-model:value="form.taxpayerIdentificationNumber" placeholder="请输入纳税人识别号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="银行账号" name="accountNumber">
|
||||
<a-input v-model:value="form.accountNumber" placeholder="请输入银行账号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="开户行" name="bankName">
|
||||
<a-input v-model:value="form.bankName" placeholder="请输入开户行" />
|
||||
</a-form-item>
|
||||
<a-form-item label="启用状态" name="disabledFlag">
|
||||
<a-switch v-model:checked="enabledChecked" @change="enabledCheckedChange" />
|
||||
</a-form-item>
|
||||
<a-form-item label="备注" name="remark">
|
||||
<a-textarea v-model:value="form.remark" :rows="2" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { invoiceApi } from '/@/api/business/oa/invoice-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const props = defineProps({
|
||||
enterpriseId: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
// emit
|
||||
const emit = defineEmits(['reloadList']);
|
||||
|
||||
// --------------------- modal 显示与隐藏 ---------------------
|
||||
// 是否展示
|
||||
const visible = ref(false);
|
||||
const enabledChecked = ref(true);
|
||||
|
||||
function enabledCheckedChange(checked) {
|
||||
form.disabledFlag = !checked;
|
||||
}
|
||||
|
||||
function showModal(rowData) {
|
||||
Object.assign(form, formDefault);
|
||||
if (rowData) {
|
||||
Object.assign(form, rowData);
|
||||
enabledChecked.value = !rowData.disabledFlag;
|
||||
}
|
||||
form.enterpriseId = props.enterpriseId;
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
formRef.value.resetFields();
|
||||
Object.assign(form, formDefault);
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
// --------------------- 表单 ---------------------
|
||||
|
||||
// 组件
|
||||
const formRef = ref();
|
||||
|
||||
const formDefault = {
|
||||
invoiceId: undefined,
|
||||
enterpriseId: undefined,
|
||||
bankName: '',
|
||||
accountNumber: '',
|
||||
invoiceHeads: '',
|
||||
taxpayerIdentificationNumber: '',
|
||||
disabledFlag: false,
|
||||
remark: '',
|
||||
};
|
||||
let form = reactive({ ...formDefault });
|
||||
const rules = {
|
||||
invoiceHeads: [{ required: true, message: '请输入开票抬头' }],
|
||||
taxpayerIdentificationNumber: [{ required: true, message: '请输入纳税人识别号' }],
|
||||
accountNumber: [{ required: true, message: '请输入银行账号' }],
|
||||
bankName: [{ required: true, message: '请输入开户行' }],
|
||||
};
|
||||
|
||||
function onSubmit() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
if (form.invoiceId) {
|
||||
await invoiceApi.update(form);
|
||||
} else {
|
||||
await invoiceApi.create(form);
|
||||
}
|
||||
message.success(`${form.invoiceId ? '修改' : '添加'}成功`);
|
||||
emit('reloadList');
|
||||
onClose();
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
});
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,243 @@
|
||||
<template>
|
||||
<a-modal :visible="visible" title="添加" :width="700" forceRender ok-text="确认" cancel-text="取消" @ok="onSubmit" @cancel="onClose">
|
||||
<a-form ref="formRef" :model="form" :rules="rules" :label-col="{ span: 6 }">
|
||||
<a-form-item label="企业名称" name="enterpriseName">
|
||||
<a-input v-model:value="form.enterpriseName" placeholder="请输入企业名称" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="企业logo" name="enterpriseLogo">
|
||||
<Upload
|
||||
accept=".jpg,.jpeg,.png,.gif"
|
||||
:maxUploadSize="1"
|
||||
buttonText="点击上传企业logo"
|
||||
:default-file-list="form.enterpriseLogo"
|
||||
@change="enterpriseLogoChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="统一社会信用代码" name="unifiedSocialCreditCode">
|
||||
<a-input v-model:value="form.unifiedSocialCreditCode" placeholder="请输入统一社会信用代码" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="类型" name="type">
|
||||
<SmartEnumSelect width="100%" v-model:value="form.type" placeholder="请选择类型" enum-name="ENTERPRISE_TYPE_ENUM" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="联系人" name="contact">
|
||||
<a-input v-model:value="form.contact" placeholder="请输入联系人" />
|
||||
</a-form-item>
|
||||
<a-form-item label="联系人电话" name="contactPhone">
|
||||
<a-input v-model:value="form.contactPhone" placeholder="请输入联系人电话" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="所在城市" name="provinceCityDistrict">
|
||||
<AreaCascader type="province_city_district" style="width: 100%" v-model:value="area" placeholder="请选择所在城市" @change="changeArea" />
|
||||
</a-form-item>
|
||||
<a-form-item label="详细地址" name="address">
|
||||
<a-input v-model:value="form.address" placeholder="请输入详细地址" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="邮箱" name="email">
|
||||
<a-input v-model:value="form.email" placeholder="请输入邮箱" />
|
||||
</a-form-item>
|
||||
<a-form-item label="启用状态" name="disabledFlag">
|
||||
<a-switch v-model:checked="enabledChecked" @change="enabledCheckedChange" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="营业执照" name="businessLicense">
|
||||
<Upload
|
||||
accept=".jpg,.jpeg,.png,.gif"
|
||||
:maxUploadSize="1"
|
||||
buttonText="点击上传营业执照"
|
||||
:default-file-list="form.businessLicense"
|
||||
@change="businessLicenseChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { message } from 'ant-design-vue';
|
||||
import _ from 'lodash';
|
||||
import { nextTick, reactive, ref } from 'vue';
|
||||
import { enterpriseApi } from '/@/api/business/oa/enterprise-api';
|
||||
import AreaCascader from '/@/components/framework/area-cascader/index.vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import Upload from '/@/components/support/file-upload/index.vue';
|
||||
import { regular } from '/@/constants/regular-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import SmartEnumSelect from '/@/components/framework/smart-enum-select/index.vue';
|
||||
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
const emit = defineEmits('refresh');
|
||||
|
||||
// --------------------- modal 显示与隐藏 ---------------------
|
||||
// 是否展示
|
||||
const visible = ref(false);
|
||||
|
||||
function showModal(enterpriseId) {
|
||||
Object.assign(form, formDefault);
|
||||
area.value = [];
|
||||
if (enterpriseId) {
|
||||
detail(enterpriseId);
|
||||
}
|
||||
visible.value = true;
|
||||
}
|
||||
|
||||
function onClose() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
async function detail(enterpriseId) {
|
||||
try {
|
||||
let result = await enterpriseApi.detail(enterpriseId);
|
||||
let data = result.data;
|
||||
Object.assign(form, data);
|
||||
nextTick(() => {
|
||||
// 省市区不存在,不需要赋值
|
||||
if (!data.provinceName) {
|
||||
return;
|
||||
}
|
||||
area.value = [
|
||||
{
|
||||
value: data.province,
|
||||
label: data.provinceName,
|
||||
},
|
||||
{
|
||||
value: data.city,
|
||||
label: data.cityName,
|
||||
},
|
||||
{
|
||||
value: data.district,
|
||||
label: data.districtName,
|
||||
},
|
||||
];
|
||||
});
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------- 表单 ---------------------
|
||||
|
||||
// 组件
|
||||
const formRef = ref();
|
||||
|
||||
const formDefault = {
|
||||
enterpriseId: undefined,
|
||||
enterpriseName: undefined,
|
||||
unifiedSocialCreditCode: undefined,
|
||||
businessLicense: undefined,
|
||||
contact: undefined,
|
||||
enterpriseLogo:undefined,
|
||||
contactPhone: undefined,
|
||||
email: undefined,
|
||||
province: undefined,
|
||||
provinceName: undefined,
|
||||
city: undefined,
|
||||
cityName: undefined,
|
||||
district: undefined,
|
||||
districtName: undefined,
|
||||
address: undefined,
|
||||
disabledFlag: false,
|
||||
};
|
||||
let form = reactive({ ...formDefault });
|
||||
const rules = {
|
||||
enterpriseName: [{ required: true, message: '请输入企业名称' }],
|
||||
unifiedSocialCreditCode: [{ required: true, message: '请输入统一社会信用代码' }],
|
||||
contact: [{ required: true, message: '请输入联系人' }],
|
||||
contactPhone: [
|
||||
{ required: true, message: '请输入联系人电话' },
|
||||
{ pattern: regular.phone, message: '请输入正确的联系人电话', trigger: 'blur' },
|
||||
],
|
||||
type: [{ required: true, message: '请选择类型' }],
|
||||
};
|
||||
|
||||
function onSubmit() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(async () => {
|
||||
SmartLoading.show();
|
||||
try {
|
||||
if (form.enterpriseId) {
|
||||
await enterpriseApi.update(form);
|
||||
} else {
|
||||
await enterpriseApi.create(form);
|
||||
}
|
||||
message.success(`${form.enterpriseId ? '修改' : '添加'}成功`);
|
||||
emit('refresh');
|
||||
onClose();
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error', error);
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
});
|
||||
}
|
||||
|
||||
// 状态
|
||||
const enabledChecked = ref(true);
|
||||
|
||||
function enabledCheckedChange(checked) {
|
||||
form.disabledFlag = !checked;
|
||||
}
|
||||
|
||||
// 地区
|
||||
const area = ref([]);
|
||||
|
||||
function changeArea(value, selectedOptions) {
|
||||
Object.assign(form, {
|
||||
province: '',
|
||||
provinceName: '',
|
||||
city: '',
|
||||
cityName: '',
|
||||
district: '',
|
||||
districtName: '',
|
||||
});
|
||||
if (!_.isEmpty(selectedOptions)) {
|
||||
// 地区信息
|
||||
form.province = area.value[0].value;
|
||||
form.provinceName = area.value[0].label;
|
||||
|
||||
form.city = area.value[1].value;
|
||||
form.cityName = area.value[1].label;
|
||||
if (area.value[2]) {
|
||||
form.district = area.value[2].value;
|
||||
form.districtName = area.value[2].label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function enterpriseLogoChange(fileList) {
|
||||
form.enterpriseLogo = fileList;
|
||||
}
|
||||
|
||||
function businessLicenseChange(fileList) {
|
||||
form.businessLicense = fileList;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.form-width {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
:deep(.ant-card-body) {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,130 @@
|
||||
<!--
|
||||
* 公司 详情
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-15 20:15:49
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<div class="detail-header">
|
||||
<a-page-header :title="detail.enterpriseName" :avatar="{ src: logo }">
|
||||
<template #extra>
|
||||
<a-button @click="showUpdate" type="primary">编辑</a-button>
|
||||
</template>
|
||||
<div>
|
||||
<a-descriptions size="small" :column="3">
|
||||
<a-descriptions-item label="统一社会信用代码">{{ detail.unifiedSocialCreditCode }}</a-descriptions-item>
|
||||
<a-descriptions-item label="联系人">{{ detail.contact }}</a-descriptions-item>
|
||||
<a-descriptions-item label="联系人电话">{{ detail.contactPhone }}</a-descriptions-item>
|
||||
<a-descriptions-item label="邮箱">{{ detail.email }}</a-descriptions-item>
|
||||
<a-descriptions-item label="所在城市">{{ area }}</a-descriptions-item>
|
||||
<a-descriptions-item label="详细地址">{{ detail.address }}</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间">{{ detail.createTime }}</a-descriptions-item>
|
||||
<a-descriptions-item label="创建人">{{ detail.createUserName }}</a-descriptions-item>
|
||||
<a-descriptions-item label="营业执照">
|
||||
<FilePreview :default-file-list="detail.businessLicense" />
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</div>
|
||||
</a-page-header>
|
||||
</div>
|
||||
<a-card class="smart-margin-top10" size="small">
|
||||
<a-tabs>
|
||||
<a-tab-pane key="employee" tab="员工信息">
|
||||
<EmployeeList :enterpriseId="enterpriseId" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="bank" tab="银行信息">
|
||||
<BankList :enterpriseId="enterpriseId" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="invoice" tab="发票信息">
|
||||
<InvoiceList :enterpriseId="enterpriseId" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="dataTracer" tab="变更记录">
|
||||
<DataTracer :dataId="enterpriseId" :type="DATA_TRACER_TYPE_ENUM.OA_ENTERPRISE.value" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<EnterpriseOperate ref="operateRef" @refresh="getDetail" />
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import _ from 'lodash';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import BankList from './components/enterprise-bank-list.vue';
|
||||
import EmployeeList from './components/enterprise-employee-list.vue';
|
||||
import InvoiceList from './components/enterprise-invoice-list.vue';
|
||||
import EnterpriseOperate from './components/enterprise-operate-modal.vue';
|
||||
import { enterpriseApi } from '/@/api/business/oa/enterprise-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import DataTracer from '/@/components/support/data-tracer/index.vue';
|
||||
import FilePreview from '/@/components/support/file-preview/index.vue';
|
||||
import { DATA_TRACER_TYPE_ENUM } from '/@/constants/support/data-tracer-const';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const route = useRoute();
|
||||
let enterpriseId = ref();
|
||||
onMounted(() => {
|
||||
if (route.query.enterpriseId) {
|
||||
enterpriseId.value = Number(route.query.enterpriseId);
|
||||
getDetail();
|
||||
}
|
||||
});
|
||||
|
||||
//编辑
|
||||
const operateRef = ref();
|
||||
function showUpdate(){
|
||||
operateRef.value.showModal(enterpriseId.value);
|
||||
}
|
||||
|
||||
// 详情
|
||||
let detail = ref({});
|
||||
|
||||
async function getDetail() {
|
||||
try {
|
||||
let result = await enterpriseApi.detail(enterpriseId.value);
|
||||
detail.value = result.data;
|
||||
} catch (error) {
|
||||
smartSentry.captureError(error);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// 地区
|
||||
const area = computed(() => {
|
||||
let area = '';
|
||||
if (!detail.value) {
|
||||
return area;
|
||||
}
|
||||
if (detail.value.provinceName) {
|
||||
area = area + detail.value.provinceName;
|
||||
}
|
||||
if (detail.value.cityName) {
|
||||
area = area + detail.value.cityName;
|
||||
}
|
||||
if (detail.value.districtName) {
|
||||
area = area + detail.value.districtName;
|
||||
}
|
||||
return area;
|
||||
});
|
||||
|
||||
const logo = computed(() => {
|
||||
if (!detail.value) {
|
||||
return '';
|
||||
}
|
||||
if (!_.isEmpty(detail.value.enterpriseLogo)) {
|
||||
return detail.value.enterpriseLogo[0].fileUrl;
|
||||
}
|
||||
return '';
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.detail-header {
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,264 @@
|
||||
<!--
|
||||
* 公司列表
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-15 20:15:49
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-form class="smart-query-form" v-privilege="'enterprise:query'">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 300px" v-model:value="queryForm.keywords" placeholder="企业名称/联系人/联系电话" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="创建时间" class="smart-query-form-item">
|
||||
<a-space direction="vertical" :size="12">
|
||||
<a-range-picker v-model:value="searchDate" @change="dateChange" />
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button type="primary" @click="ajaxQuery">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="resetQuery">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false" :hoverable="true">
|
||||
<a-row class="smart-table-btn-block">
|
||||
<div class="smart-table-operate-block">
|
||||
<a-button @click="add()" v-privilege="'enterprise:add'" type="primary" size="small">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新建企业
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="smart-table-setting-block">
|
||||
<TableOperator v-model="columns" :tableId="TABLE_ID_CONST.BUSINESS.OA.ENTERPRISE" :refresh="ajaxQuery" />
|
||||
</div>
|
||||
</a-row>
|
||||
|
||||
<a-table
|
||||
:scroll="{ x: 1300 }"
|
||||
size="small"
|
||||
:dataSource="tableData"
|
||||
:columns="columns"
|
||||
rowKey="enterpriseId"
|
||||
:pagination="false"
|
||||
:loading="tableLoading"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ column, record, text }">
|
||||
<template v-if="column.dataIndex === 'disabledFlag'">
|
||||
{{ text ? '禁用' : '启用' }}
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'enterpriseName'">
|
||||
<a @click="detail(record.enterpriseId)">{{ record.enterpriseName }}</a>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'type'">
|
||||
<span>{{ $smartEnumPlugin.getDescByValue('ENTERPRISE_TYPE_ENUM', text) }}</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button @click="update(record.enterpriseId)" v-privilege="'enterprise:edit'" type="link">编辑</a-button>
|
||||
<a-button @click="confirmDelete(record.enterpriseId)" danger v-privilege="'enterprise:delete'" type="link">删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="ajaxQuery"
|
||||
@showSizeChange="ajaxQuery"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
<EnterpriseOperate ref="operateRef" @refresh="ajaxQuery" />
|
||||
</a-card>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { enterpriseApi } from '/@/api/business/oa/enterprise-api';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import { useRouter } from 'vue-router';
|
||||
import EnterpriseOperate from './components/enterprise-operate-modal.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||||
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||||
|
||||
// --------------------------- 企业表格 列 ---------------------------
|
||||
|
||||
const columns = ref([
|
||||
{
|
||||
title: '企业名称',
|
||||
dataIndex: 'enterpriseName',
|
||||
minWidth: 180,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '统一社会信用代码',
|
||||
dataIndex: 'unifiedSocialCreditCode',
|
||||
minWidth: 170,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '企业类型',
|
||||
dataIndex: 'type',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '联系人',
|
||||
width: 100,
|
||||
dataIndex: 'contact',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '联系人电话',
|
||||
width: 120,
|
||||
dataIndex: 'contactPhone',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
minWidth: 100,
|
||||
dataIndex: 'email',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
width: 50,
|
||||
dataIndex: 'disabledFlag',
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
width: 60,
|
||||
dataIndex: 'createUserName',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 100,
|
||||
},
|
||||
]);
|
||||
|
||||
// --------------------------- 查询 ---------------------------
|
||||
|
||||
const queryFormState = {
|
||||
keywords: '',
|
||||
endTime: null,
|
||||
startTime: null,
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
searchCount: true,
|
||||
};
|
||||
const queryForm = reactive({ ...queryFormState });
|
||||
const tableLoading = ref(false);
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
|
||||
// 日期选择
|
||||
let searchDate = ref();
|
||||
|
||||
function dateChange(dates, dateStrings) {
|
||||
queryForm.startTime = dateStrings[0];
|
||||
queryForm.endTime = dateStrings[1];
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
searchDate.value = [];
|
||||
Object.assign(queryForm, queryFormState);
|
||||
ajaxQuery();
|
||||
}
|
||||
|
||||
async function ajaxQuery() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
let responseModel = await enterpriseApi.pageQuery(queryForm);
|
||||
const list = responseModel.data.list;
|
||||
total.value = responseModel.data.total;
|
||||
tableData.value = list;
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------- 删除 ---------------------------
|
||||
|
||||
function confirmDelete(enterpriseId) {
|
||||
Modal.confirm({
|
||||
title: '确定要删除吗?',
|
||||
content: '删除后,该信息将不可恢复',
|
||||
okText: '删除',
|
||||
okType: 'danger',
|
||||
onOk() {
|
||||
del(enterpriseId);
|
||||
},
|
||||
cancelText: '取消',
|
||||
onCancel() {},
|
||||
});
|
||||
}
|
||||
|
||||
async function del(enterpriseId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
await enterpriseApi.delete(enterpriseId);
|
||||
message.success('删除成功');
|
||||
ajaxQuery();
|
||||
} catch (e) {
|
||||
smartSentry.captureError(e);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------- 增加、修改、详情 ---------------------------
|
||||
|
||||
let router = useRouter();
|
||||
const operateRef = ref();
|
||||
function add() {
|
||||
operateRef.value.showModal();
|
||||
}
|
||||
|
||||
function update(enterpriseId) {
|
||||
operateRef.value.showModal(enterpriseId);
|
||||
}
|
||||
|
||||
function detail(enterpriseId) {
|
||||
router.push({ path: '/oa/enterprise/enterprise-detail', query: { enterpriseId: enterpriseId } });
|
||||
}
|
||||
|
||||
onMounted(ajaxQuery);
|
||||
</script>
|
||||
@@ -0,0 +1,307 @@
|
||||
<!--
|
||||
* 通知 表单
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-drawer
|
||||
:title="formData.noticeId ? '编辑' : '新建'"
|
||||
:visible="visibleFlag"
|
||||
:width="1000"
|
||||
:footerStyle="{ textAlign: 'right' }"
|
||||
@close="onClose"
|
||||
:destroyOnClose="true"
|
||||
>
|
||||
<a-form ref="formRef" :model="formData" :rules="formRules" :label-col="{ span: 3 }" :wrapper-col="{ span: 20 }">
|
||||
<a-form-item label="公告标题" name="title">
|
||||
<a-input v-model:value="formData.title" placeholder="请输入公告标题" />
|
||||
</a-form-item>
|
||||
<a-form-item label="分类" name="noticeTypeId">
|
||||
<a-select v-model:value="formData.noticeTypeId" style="width: 100%" :showSearch="true" :allowClear="true">
|
||||
<a-select-option v-for="item in noticeTypeList" :key="item.noticeTypeId" :value="item.noticeTypeId">
|
||||
{{ item.noticeTypeName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="文号">
|
||||
<a-input v-model:value="formData.documentNumber" placeholder="文号,如:1024创新实验室发〔2022〕字第36号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="作者" name="author">
|
||||
<a-input v-model:value="formData.author" placeholder="请输入作者" />
|
||||
</a-form-item>
|
||||
<a-form-item label="来源" name="source">
|
||||
<a-input v-model:value="formData.source" placeholder="请输入来源" />
|
||||
</a-form-item>
|
||||
<a-form-item label="可见范围" name="allVisibleFlag">
|
||||
<a-select v-model:value="formData.allVisibleFlag" placeholder="请选择可见范围">
|
||||
<a-select-option :value="1">全部可见</a-select-option>
|
||||
<a-select-option :value="0">部分可见</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item v-show="!formData.allVisibleFlag" label="可见员工/部门">
|
||||
<a-button type="primary" @click="showNoticeVisibleModal">选择</a-button>
|
||||
<div class="visible-list">
|
||||
<div class="visible-item" v-for="(item, index) in formData.visibleRangeList" :key="item.dataId">
|
||||
<a-tag>
|
||||
<span>{{ item.dataName }}</span>
|
||||
<close-outlined @click="removeVisibleItem(index)" />
|
||||
</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item label="定时发布">
|
||||
<a-switch
|
||||
v-model:checked="formData.scheduledPublishFlag"
|
||||
checked-children="开"
|
||||
un-checked-children="关"
|
||||
@change="changesSheduledPublishFlag"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item v-show="formData.scheduledPublishFlag" label="发布时间">
|
||||
<a-date-picker
|
||||
v-model:value="releaseTime"
|
||||
:format="timeFormat"
|
||||
showTime
|
||||
:allowClear="false"
|
||||
placeholder="请选择发布时间"
|
||||
style="width: 200px"
|
||||
@change="changeTime"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="公告内容" name="contentHtml">
|
||||
<SmartWangeditor ref="contentRef" :modelValue="formData.contentHtml" :height="300" />
|
||||
</a-form-item>
|
||||
<a-form-item label="附件">
|
||||
<Upload
|
||||
:defaultFileList="defaultFileList"
|
||||
:maxUploadSize="10"
|
||||
:folder="FILE_FOLDER_TYPE_ENUM.NOTICE.value"
|
||||
buttonText="上传附件"
|
||||
listType="text"
|
||||
extraMsg="最多上传10个附件"
|
||||
@change="changeAttachment"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<template #footer>
|
||||
<a-space>
|
||||
<a-button @click="onClose">取消</a-button>
|
||||
<a-button type="primary" @click="onSubmit">保存</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-drawer>
|
||||
|
||||
<!-- 选择可见范围弹窗 -->
|
||||
<NoticeFormVisibleModal ref="noticeFormVisibleModal" @selectedFinish="finishCanSelectedVisibleRange" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted, watch, computed, nextTick } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import lodash from 'lodash';
|
||||
import dayjs, { Dayjs } from 'dayjs';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import { FILE_FOLDER_TYPE_ENUM } from '/@/constants/support/file-const';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import SmartWangeditor from '/@/components/framework/wangeditor/index.vue';
|
||||
import Upload from '/@/components/support/file-upload/index.vue';
|
||||
import NoticeFormVisibleModal from './notice-form-visible-modal.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const emits = defineEmits(['reloadList']);
|
||||
|
||||
// ------------------ 显示,关闭 ------------------
|
||||
// 显示
|
||||
const visibleFlag = ref(false);
|
||||
function showModal(noticeId) {
|
||||
Object.assign(formData, defaultFormData);
|
||||
releaseTime.value = null;
|
||||
defaultFileList.value = [];
|
||||
queryNoticeTypeList();
|
||||
if (noticeId) {
|
||||
getNoticeUpdate(noticeId);
|
||||
}
|
||||
|
||||
visibleFlag.value = true;
|
||||
nextTick(() => {
|
||||
formRef.value.clearValidate();
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭
|
||||
function onClose() {
|
||||
visibleFlag.value = false;
|
||||
}
|
||||
|
||||
// ------------------ 表单 ------------------
|
||||
|
||||
const formRef = ref();
|
||||
const contentRef = ref();
|
||||
const noticeFormVisibleModal = ref();
|
||||
|
||||
const defaultFormData = {
|
||||
noticeId: undefined,
|
||||
noticeTypeId: undefined,
|
||||
title: undefined, // 标题
|
||||
categoryId: undefined, // 分类
|
||||
source: undefined, // 来源
|
||||
documentNumber: undefined, // 文号
|
||||
author: undefined, // 作者
|
||||
allVisibleFlag: 1, // 是否全部可见
|
||||
visibleRangeList: [], // 可见范围
|
||||
scheduledPublishFlag: false, // 是否定时发布
|
||||
publishTime: undefined, // 发布时间
|
||||
attachment: [], // 附件
|
||||
contentHtml: '', // html内容
|
||||
contentText: '', // 纯文本内容
|
||||
};
|
||||
|
||||
const formData = reactive({ ...defaultFormData });
|
||||
|
||||
const formRules = {
|
||||
title: [{ required: true, message: '请输入' }],
|
||||
noticeTypeId: [{ required: true, message: '请选择分类' }],
|
||||
allVisibleFlag: [{ required: true, message: '请选择' }],
|
||||
source: [{ required: true, message: '请输入来源' }],
|
||||
author: [{ required: true, message: '请输入作者' }],
|
||||
contentHtml: [{ required: true, message: '请输入内容' }],
|
||||
};
|
||||
|
||||
// 查询详情
|
||||
async function getNoticeUpdate(noticeId) {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
const result = await noticeApi.getUpdateNoticeInfo(noticeId);
|
||||
const attachment = result.data.attachment;
|
||||
if (!lodash.isEmpty(attachment)) {
|
||||
defaultFileList.value = attachment;
|
||||
} else {
|
||||
defaultFileList.value = [];
|
||||
}
|
||||
Object.assign(formData, result.data);
|
||||
formData.allVisibleFlag = formData.allVisibleFlag ? 1 : 0;
|
||||
|
||||
releaseTime.value = dayjs(result.data.publishTime);
|
||||
visibleFlag.value = true;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// 点击确定,验证表单
|
||||
async function onSubmit() {
|
||||
try {
|
||||
formData.contentHtml = contentRef.value.getHtml();
|
||||
formData.contentText = contentRef.value.getText();
|
||||
await formRef.value.validateFields();
|
||||
save();
|
||||
} catch (err) {
|
||||
message.error('参数验证错误,请仔细填写表单数据!');
|
||||
}
|
||||
}
|
||||
|
||||
// 新建、编辑API
|
||||
async function save() {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
if (formData.allVisibleFlag) {
|
||||
formData.visibleRangeList = [];
|
||||
}
|
||||
if (!formData.publishTime) {
|
||||
formData.publishTime = dayjs().format(timeFormat);
|
||||
}
|
||||
if (formData.noticeId) {
|
||||
await noticeApi.updateNotice(formData);
|
||||
} else {
|
||||
await noticeApi.addNotice(formData);
|
||||
}
|
||||
message.success('保存成功');
|
||||
emits('reloadList');
|
||||
onClose();
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ 通知分类 ------------------
|
||||
|
||||
// 查询分类列表
|
||||
const noticeTypeList = ref([]);
|
||||
async function queryNoticeTypeList() {
|
||||
try {
|
||||
const result = await noticeApi.getAllNoticeTypeList();
|
||||
noticeTypeList.value = result.data;
|
||||
if (noticeTypeList.value.length > 0 && !formData.noticeId) {
|
||||
formData.noticeTypeId = noticeTypeList.value[0].noticeTypeId;
|
||||
}
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------- 可见员工/部门 ----------------------------
|
||||
// 点击显示选择可见员工/部门
|
||||
function showNoticeVisibleModal() {
|
||||
const visibleRangeList = formData.visibleRangeList || [];
|
||||
noticeFormVisibleModal.value.showModal(visibleRangeList);
|
||||
}
|
||||
|
||||
// 选择完成回调
|
||||
function finishCanSelectedVisibleRange(selectedList) {
|
||||
formData.visibleRangeList = selectedList;
|
||||
}
|
||||
|
||||
// 移除某个员工/部门
|
||||
function removeVisibleItem(index) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确定移除吗?',
|
||||
onOk() {
|
||||
formData.visibleRangeList.splice(index, 1);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------------- 发布时间 ----------------------------
|
||||
const timeFormat = 'YYYY-MM-DD HH:mm:ss';
|
||||
const releaseTime = ref(null);
|
||||
function changeTime(date, dateString) {
|
||||
formData.publishTime = dateString;
|
||||
}
|
||||
function changesSheduledPublishFlag(checked) {
|
||||
releaseTime.value = checked ? dayjs() : null;
|
||||
formData.publishTime = checked ? dayjs().format(timeFormat) : null;
|
||||
}
|
||||
|
||||
// ----------------------- 上传附件 ----------------------------
|
||||
// 已上传的附件列表
|
||||
const defaultFileList = ref([]);
|
||||
function changeAttachment(fileList) {
|
||||
defaultFileList.value = fileList;
|
||||
formData.attachment = lodash.isEmpty(fileList) ? [] : fileList;
|
||||
}
|
||||
|
||||
// ----------------------- 以下是暴露的方法内容 ------------------------
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.visible-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.visible-item {
|
||||
padding-top: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,71 @@
|
||||
<!--
|
||||
* 通知 可见范围
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-modal title="选择部门" v-model:visible="visibleFlag" :maskClosable="false" :width="768" @ok="onSubmit" @cancel="onClose">
|
||||
<a-tabs v-model:activeKey="activeKey">
|
||||
<a-tab-pane :key="1" tab="选择员工">
|
||||
<NoticeFormVisibleTransferEmployee :employeeList="employeeList" @onChange="onChangeEmployee" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane :key="2" tab="选择部门">
|
||||
<NoticeFormVisibleTransferDepartment :departmentList="departmentList" @onChange="onChangeDepartment" />
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted, watch } from 'vue';
|
||||
import { NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM } from '/@/constants/business/oa/notice-const';
|
||||
import NoticeFormVisibleTransferDepartment from './notice-form-visible-transfer-department.vue';
|
||||
import NoticeFormVisibleTransferEmployee from './notice-form-visible-transfer-employee.vue';
|
||||
|
||||
const emits = defineEmits('selectedFinish');
|
||||
const visibleFlag = ref(false);
|
||||
function onClose() {
|
||||
visibleFlag.value = false;
|
||||
}
|
||||
|
||||
const activeKey = ref(1);
|
||||
// 已选的员工列表
|
||||
const employeeList = ref([]);
|
||||
// 已选的部门列表
|
||||
const departmentList = ref([]);
|
||||
|
||||
// 显示弹窗
|
||||
function showModal(visibleRangeList = []) {
|
||||
employeeList.value = visibleRangeList.filter((item) => item.dataType === NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.EMPLOYEE.value);
|
||||
departmentList.value = visibleRangeList.filter((item) => item.dataType === NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.DEPARTMENT.value);
|
||||
activeKey.value = 1;
|
||||
visibleFlag.value = true;
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
const selectedList = [...employeeList.value, ...departmentList.value];
|
||||
emits('selectedFinish', selectedList);
|
||||
onClose();
|
||||
}
|
||||
|
||||
// 选择员工改变
|
||||
function onChangeEmployee({ selectedList }) {
|
||||
employeeList.value = selectedList;
|
||||
}
|
||||
|
||||
// 选择部门改变
|
||||
function onChangeDepartment({ selectedList }) {
|
||||
departmentList.value = selectedList;
|
||||
}
|
||||
|
||||
// ----------------------- 以下是暴露的方法内容 ------------------------
|
||||
defineExpose({
|
||||
showModal,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -0,0 +1,204 @@
|
||||
<!--
|
||||
* 通知 可见范围 选择部门
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="sider-fl">
|
||||
<a-tree :tree-data="treeData" :fieldNames="{ title: 'name', key: 'departmentId' }" :selectable="false" v-model:expandedKeys="expandedKeys">
|
||||
<template #switcherIcon="{ switcherCls }">
|
||||
<caret-down-outlined :class="switcherCls" />
|
||||
</template>
|
||||
<template #title="{ name, departmentId }">
|
||||
<div class="list-item" :class="{ active: checkExists(departmentId) }">
|
||||
<div class="list-item-title">{{ name }}</div>
|
||||
<check-circle-filled class="check-icon-style" @click="onSelectAdd(name, departmentId)" />
|
||||
</div>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
<div class="sider-fr">
|
||||
<div class="selected-list">
|
||||
<div class="list-item" v-for="(item, index) in selectedList" :key="item.dataId">
|
||||
<div class="list-item-title">{{ item.dataName }}</div>
|
||||
<close-circle-two-tone @click="onRemove(index)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted, watch, computed, nextTick } from 'vue';
|
||||
import lodash from 'lodash';
|
||||
import { NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM } from '/@/constants/business/oa/notice-const';
|
||||
import { departmentApi } from '/@/api/system/department/department-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const props = defineProps({
|
||||
// 已选择的部门数据列表
|
||||
departmentList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['onChange']);
|
||||
|
||||
const treeData = ref([]);
|
||||
async function queryDepartmentTree() {
|
||||
try {
|
||||
const result = await departmentApi.queryDepartmentTree();
|
||||
if (!lodash.isEmpty(result.data)) {
|
||||
treeData.value = result.data;
|
||||
setExpanded();
|
||||
}
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认展开的节点
|
||||
const expandedKeys = ref([]);
|
||||
function setExpanded() {
|
||||
expandedKeys.value = [treeData.value[0].departmentId];
|
||||
}
|
||||
|
||||
// 选择的部门列表数据
|
||||
const selectedList = ref([]);
|
||||
|
||||
// 选择的部门列表Ids
|
||||
const selectedIds = computed(() => {
|
||||
return selectedList.value.map((item) => item.dataId);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.departmentList,
|
||||
(newVal) => {
|
||||
selectedList.value = newVal;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 检查是否已选
|
||||
function checkExists(dataId) {
|
||||
return selectedIds.value.includes(dataId);
|
||||
}
|
||||
|
||||
// 点击左边添加
|
||||
function onSelectAdd(name, departmentId) {
|
||||
if (checkExists(departmentId)) {
|
||||
return;
|
||||
}
|
||||
selectedList.value.push({
|
||||
dataName: name,
|
||||
dataId: departmentId,
|
||||
dataType: NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.DEPARTMENT.value,
|
||||
});
|
||||
onChangeEmit();
|
||||
}
|
||||
|
||||
// 点击右边移除
|
||||
function onRemove(index) {
|
||||
selectedList.value.splice(index, 1);
|
||||
onChangeEmit();
|
||||
}
|
||||
|
||||
function onChangeEmit() {
|
||||
emits('onChange', { selectedList: selectedList.value, selectedIds: selectedIds.value });
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
queryDepartmentTree();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ant-tree-list-holder-inner) {
|
||||
display: block !important;
|
||||
.ant-tree-treenode {
|
||||
align-items: center;
|
||||
padding-bottom: 0;
|
||||
&:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.ant-tree-switcher {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.ant-tree-switcher-icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.ant-tree-node-content-wrapper {
|
||||
display: block;
|
||||
flex: 1;
|
||||
&:hover {
|
||||
cursor: auto;
|
||||
}
|
||||
.ant-tree-title {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
.sider-fl,
|
||||
.sider-fr {
|
||||
flex: 1;
|
||||
height: 500px;
|
||||
border: 1px solid #d9d9d9;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background-color: #ededed;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
height: 50px;
|
||||
background-color: #a1a1a1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
.sider-fr {
|
||||
margin-left: 15px;
|
||||
.list-item {
|
||||
padding-left: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 14px 0 0;
|
||||
height: 32px;
|
||||
&:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
&.active {
|
||||
.check-icon-style {
|
||||
cursor: auto;
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
.list-item-title {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.check-icon-style {
|
||||
color: #d9d9d9;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,252 @@
|
||||
<!--
|
||||
* 通知 可见范围 选择员工
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="sider-left">
|
||||
<a-tree :tree-data="treeData" :fieldNames="{ title: 'name' }" :selectable="false" v-model:expandedKeys="expandedKeys">
|
||||
<template #switcherIcon="{ switcherCls }">
|
||||
<caret-down-outlined :class="switcherCls" />
|
||||
</template>
|
||||
<template #title="{ name, id, dataType }">
|
||||
<div class="list-item" :class="{ active: checkExists(id) }">
|
||||
<div class="list-item-title">
|
||||
<user-outlined v-if="dataType === NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.EMPLOYEE.value" />
|
||||
{{ name }}
|
||||
</div>
|
||||
<check-circle-filled
|
||||
v-if="dataType === NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.EMPLOYEE.value"
|
||||
class="check-icon-style"
|
||||
@click="onSelectAdd(name, id, dataType)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
<div class="sider-right">
|
||||
<div class="selected-list">
|
||||
<div class="list-item" v-for="(item, index) in selectedList" :key="item.id">
|
||||
<div class="list-item-title">{{ item.dataName }}</div>
|
||||
<close-circle-two-tone @click="onRemove(index)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted, watch, computed, nextTick } from 'vue';
|
||||
import lodash from 'lodash';
|
||||
import { NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM } from '/@/constants/business/oa/notice-const';
|
||||
import { departmentApi } from '/@/api/system/department/department-api';
|
||||
import { employeeApi } from '/@/api/system/employee/employee-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const props = defineProps({
|
||||
// 已选择的员工数据列表
|
||||
employeeList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['onChange']);
|
||||
|
||||
const treeData = ref([]);
|
||||
|
||||
// 查询部门树形
|
||||
async function queryDepartmentTree() {
|
||||
try {
|
||||
const departmentResult = await departmentApi.queryDepartmentTree();
|
||||
const employeeResult = await employeeApi.queryAll();
|
||||
const departmentTree = departmentResult.data;
|
||||
buildDepartmentEmployeeTree(departmentTree, employeeResult.data);
|
||||
|
||||
if (!lodash.isEmpty(departmentTree)) {
|
||||
treeData.value = departmentTree;
|
||||
console.log(treeData.value);
|
||||
nextTick(() => {
|
||||
setExpanded();
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
}
|
||||
}
|
||||
|
||||
// 递归构建部门员工树
|
||||
function buildDepartmentEmployeeTree(departmentTree, employeeList) {
|
||||
for (const department of departmentTree) {
|
||||
if (department.dataType && department.dataType === NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.EMPLOYEE.value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
department.id = department.departmentId;
|
||||
department.key = 'department_' + department.departmentId;
|
||||
department.dataType = NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.DEPARTMENT.value;
|
||||
let employeeChildren = employeeList
|
||||
.filter((e) => e.departmentId === department.departmentId)
|
||||
.map((e) =>
|
||||
Object.assign(
|
||||
{},
|
||||
{
|
||||
id: e.employeeId,
|
||||
key: 'employee_' + e.employeeId,
|
||||
name: e.actualName,
|
||||
dataType: NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.EMPLOYEE.value,
|
||||
}
|
||||
)
|
||||
);
|
||||
if (!department.children) {
|
||||
department.children = [];
|
||||
}
|
||||
department.children.push(...employeeChildren);
|
||||
buildDepartmentEmployeeTree(department.children, employeeList);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认展开的节点
|
||||
const expandedKeys = ref([]);
|
||||
function setExpanded() {
|
||||
expandedKeys.value = [treeData.value[0].key];
|
||||
}
|
||||
|
||||
// 选择的员工列表数据
|
||||
const selectedList = ref([]);
|
||||
|
||||
// 选择的员工列表Ids
|
||||
const selectedIds = computed(() => {
|
||||
return selectedList.value.map((item) => item.dataId);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.employeeList,
|
||||
(newVal) => {
|
||||
selectedList.value = newVal;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 检查是否已选
|
||||
function checkExists(id) {
|
||||
return selectedIds.value.includes(id);
|
||||
}
|
||||
|
||||
// 点击左边添加
|
||||
function onSelectAdd(name, id, dataType) {
|
||||
if (checkExists(id)) {
|
||||
return;
|
||||
}
|
||||
selectedList.value.push({
|
||||
dataName: name,
|
||||
dataId: id,
|
||||
dataType: NOTICE_VISIBLE_RANGE_DATA_TYPE_ENUM.EMPLOYEE.value,
|
||||
});
|
||||
onChangeEmit();
|
||||
}
|
||||
|
||||
// 点击右边移除
|
||||
function onRemove(index) {
|
||||
selectedList.value.splice(index, 1);
|
||||
onChangeEmit();
|
||||
}
|
||||
|
||||
function onChangeEmit() {
|
||||
emits('onChange', { selectedList: selectedList.value, selectedIds: selectedIds.value });
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
queryDepartmentTree();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ant-tree-list-holder-inner) {
|
||||
display: block !important;
|
||||
.ant-tree-treenode {
|
||||
align-items: center;
|
||||
padding-bottom: 0;
|
||||
&:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
.ant-tree-switcher {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.ant-tree-switcher-icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.ant-tree-node-content-wrapper {
|
||||
display: block;
|
||||
flex: 1;
|
||||
&:hover {
|
||||
cursor: auto;
|
||||
}
|
||||
.ant-tree-title {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
.sider-left,
|
||||
.sider-right {
|
||||
flex: 1;
|
||||
height: 500px;
|
||||
border: 1px solid #d9d9d9;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
&::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-track-piece {
|
||||
background-color: #ededed;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
height: 50px;
|
||||
background-color: #a1a1a1;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
.sider-right {
|
||||
margin-left: 15px;
|
||||
.list-item {
|
||||
padding-left: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.list-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 14px 0 0;
|
||||
height: 32px;
|
||||
&:hover {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
&.active {
|
||||
.check-icon-style {
|
||||
cursor: auto;
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
.list-item-title {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.check-icon-style {
|
||||
color: #d9d9d9;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,161 @@
|
||||
<!--
|
||||
* 通知 查看记录
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<a-form class="smart-query-form">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="部门" class="smart-query-form-item" style="width: 280px; margin-right: 20px">
|
||||
<DepartmentTreeSelect v-model:value="queryForm.departmentId" width="100%" />
|
||||
</a-form-item>
|
||||
<a-form-item label="关键字" class="smart-query-form-item" style="width: 280px">
|
||||
<a-input v-model:value="queryForm.keywords" placeholder="姓名/IP/设备" />
|
||||
</a-form-item>
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button-group>
|
||||
<a-button type="primary" @click="onSearch">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="resetQuery">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
<a-table rowKey="employeeId" :columns="tableColumns" :dataSource="tableData" :pagination="false" :loading="tableLoading" size="small" bordered>
|
||||
<template #bodyCell="{ column, record, text }">
|
||||
<template v-if="column.dataIndex === 'employeeName'"> {{ text }}({{ record.departmentName }}) </template>
|
||||
<template v-if="column.dataIndex === 'firstIp'"> {{ text }} ({{ record.firstDevice }}) </template>
|
||||
<template v-if="column.dataIndex === 'lastIp'"> {{ text }} ({{ record.lastDevice }}) </template>
|
||||
</template>
|
||||
</a-table>
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryViewRecord"
|
||||
@showSizeChange="queryViewRecord"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import DepartmentTreeSelect from '/@/components/system/department-tree-select/index.vue';
|
||||
import uaparser from 'ua-parser-js';
|
||||
|
||||
const props = defineProps({
|
||||
noticeId: {
|
||||
type: [Number, String],
|
||||
},
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
onSearch,
|
||||
});
|
||||
|
||||
const tableColumns = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'employeeName',
|
||||
},
|
||||
{
|
||||
title: '查看次数',
|
||||
dataIndex: 'pageViewCount',
|
||||
},
|
||||
{
|
||||
title: '首次查看设备',
|
||||
dataIndex: 'firstIp',
|
||||
},
|
||||
{
|
||||
title: '首次查看时间',
|
||||
dataIndex: 'createTime',
|
||||
},
|
||||
{
|
||||
title: '最后一次查看设备',
|
||||
dataIndex: 'lastIp',
|
||||
},
|
||||
{
|
||||
title: '最后一次查看时间',
|
||||
dataIndex: 'updateTime',
|
||||
with: 80,
|
||||
},
|
||||
];
|
||||
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
const tableLoading = ref(false);
|
||||
|
||||
const defaultQueryForm = {
|
||||
noticeId: props.noticeId,
|
||||
departmentId: null,
|
||||
keywords: '',
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
};
|
||||
|
||||
const queryForm = reactive({ ...defaultQueryForm });
|
||||
|
||||
function buildDeviceInfo(userAgent) {
|
||||
if (!userAgent) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let ua = uaparser(userAgent);
|
||||
let browser = ua.browser.name;
|
||||
let os = ua.os.name;
|
||||
return browser + '/' + os + '/' + (ua.device.vendor ? ua.device.vendor + ua.device.model : '');
|
||||
}
|
||||
|
||||
async function queryViewRecord() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
const result = await noticeApi.queryViewRecord(queryForm);
|
||||
|
||||
for (const e of result.data.list) {
|
||||
e.firstDevice = buildDeviceInfo(e.firstUserAgent);
|
||||
e.lastDevice = buildDeviceInfo(e.lastUserAgent);
|
||||
}
|
||||
|
||||
tableData.value = result.data.list;
|
||||
total.value = result.data.total;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
// 点击查询
|
||||
function onSearch() {
|
||||
queryForm.pageNum = 1;
|
||||
queryViewRecord();
|
||||
}
|
||||
|
||||
// 点击重置
|
||||
function resetQuery() {
|
||||
Object.assign(queryForm, defaultQueryForm);
|
||||
queryViewRecord();
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,144 @@
|
||||
<!--
|
||||
* 通知 详情
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-card style="margin-bottom: 15px" size="small">
|
||||
<a-descriptions :title="noticeDetail.title" :columns="4" size="small">
|
||||
<template #extra>
|
||||
<a-button v-if="!noticeDetail.publishFlag" type="primary" size="small" @click="onEdit">编辑</a-button>
|
||||
</template>
|
||||
<a-descriptions-item label="分类">{{ noticeDetail.noticeTypeName }}</a-descriptions-item>
|
||||
<a-descriptions-item label="文号">{{ noticeDetail.documentNumber }}</a-descriptions-item>
|
||||
<a-descriptions-item label="来源">{{ noticeDetail.source }}</a-descriptions-item>
|
||||
<a-descriptions-item label="作者">{{ noticeDetail.author }}</a-descriptions-item>
|
||||
<a-descriptions-item label="页面浏览量">{{ noticeDetail.pageViewCount }}</a-descriptions-item>
|
||||
<a-descriptions-item label="用户浏览量">{{ noticeDetail.userViewCount }}</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间">{{ noticeDetail.createTime }}</a-descriptions-item>
|
||||
<a-descriptions-item label="发布时间">{{ noticeDetail.publishTime }}</a-descriptions-item>
|
||||
<a-descriptions-item label="定时发布">{{ noticeDetail.publishFlag ? '已发布' : '待发布' }}</a-descriptions-item>
|
||||
<a-descriptions-item label="删除状态">{{ noticeDetail.deletedFlag ? '已删除' : '未删除' }}</a-descriptions-item>
|
||||
<a-descriptions-item v-if="!$lodash.isEmpty(noticeDetail.attachmentFile)" label="附件">
|
||||
<div class="file-list">
|
||||
<a class="file-item" v-for="item in noticeDetail.attachmentFile" :key="item.fileId" @click="onPrevFile(item)">{{ item.fileName }}</a>
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="可见范围" :span="2">
|
||||
<template v-if="noticeDetail.allVisibleFlag">全部可见</template>
|
||||
<div class="visible-list">
|
||||
<div class="visible-item" v-for="item in noticeDetail.visibleRangeList" :key="item.dataId">
|
||||
{{ item.dataName }}
|
||||
</div>
|
||||
</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
|
||||
<a-card size="small">
|
||||
<a-tabs v-model:activeKey="activeKey" size="small">
|
||||
<a-tab-pane :key="1" tab="内容">
|
||||
<div class="content-html" v-html="noticeDetail.contentHtml"></div>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane :key="2" tab="查看记录" force-render>
|
||||
<NoticeViewRecordList ref="noticeViewRecordList" :noticeId="route.query.noticeId" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane :key="3" tab="操作记录" />
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
|
||||
<!-- 编辑 -->
|
||||
<NoticeFormDrawer ref="noticeFormDrawerRef" @reloadList="queryNoticeDetail" />
|
||||
|
||||
<!-- 预览附件 -->
|
||||
<FilePreviewModal ref="filePreviewRef" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import NoticeFormDrawer from './components/notice-form-drawer.vue';
|
||||
import NoticeViewRecordList from './components/notice-view-record-list.vue';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import FilePreviewModal from '/@/components/support/file-preview-modal/index.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const props = defineProps({
|
||||
newsType: {
|
||||
type: Number,
|
||||
},
|
||||
});
|
||||
|
||||
const activeKey = ref(1);
|
||||
|
||||
const noticeDetail = ref({});
|
||||
const noticeViewRecordList = ref();
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.noticeId) {
|
||||
queryNoticeDetail();
|
||||
noticeViewRecordList.value.onSearch();
|
||||
}
|
||||
});
|
||||
|
||||
// 查询详情
|
||||
async function queryNoticeDetail() {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
const result = await noticeApi.getUpdateNoticeInfo(route.query.noticeId);
|
||||
noticeDetail.value = result.data;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// 点击编辑
|
||||
const noticeFormDrawerRef = ref();
|
||||
function onEdit() {
|
||||
noticeFormDrawerRef.value.showModal(noticeDetail.value.noticeId);
|
||||
}
|
||||
|
||||
// 预览附件
|
||||
const filePreviewRef = ref();
|
||||
function onPrevFile(fileItem) {
|
||||
filePreviewRef.value.showPreview(fileItem);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ant-descriptions-item-content) {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.file-list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.file-item {
|
||||
display: block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.visible-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.visible-item {
|
||||
margin-right: 10px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
.content-html {
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,153 @@
|
||||
<!--
|
||||
* 通知 详情 (员工)
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-card size="small">
|
||||
<div>
|
||||
<div class="content-header">
|
||||
<!--startprint-->
|
||||
<div class="content-header-title">
|
||||
{{ noticeDetail.title }}
|
||||
</div>
|
||||
<div class="content-header-info">
|
||||
<span v-show="noticeDetail.author">作者:{{ noticeDetail.author }}</span>
|
||||
<span v-show="noticeDetail.source">来源:{{ noticeDetail.source }}</span>
|
||||
<span>发布时间:{{ noticeDetail.publishTime }}</span>
|
||||
<span>阅读量:{{ noticeDetail.pageViewCount }}</span>
|
||||
<span @click="print">【打印本页】</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-html" v-html="noticeDetail.contentHtml"></div>
|
||||
<!--endprint-->
|
||||
</div>
|
||||
<a-divider />
|
||||
<div>附件:<file-preview :fileList="noticeDetail.attachment" /></div>
|
||||
</a-card>
|
||||
|
||||
<a-card title="记录" size="small" class="smart-margin-top10">
|
||||
<NoticeViewRecordList ref="noticeViewRecordList" :noticeId="route.query.noticeId" />
|
||||
</a-card>
|
||||
|
||||
<!-- 预览附件 -->
|
||||
<FilePreviewModal ref="filePreviewRef" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import NoticeViewRecordList from './components/notice-view-record-list.vue';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import { SmartLoading } from '/@/components/framework/smart-loading';
|
||||
import FilePreviewModal from '/@/components/support/file-preview-modal/index.vue';
|
||||
import FilePreview from '/@/components/support/file-preview/index.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const activeKey = ref(1);
|
||||
|
||||
const noticeDetail = ref({});
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.noticeId) {
|
||||
queryNoticeDetail();
|
||||
}
|
||||
});
|
||||
|
||||
const noticeViewRecordList = ref();
|
||||
|
||||
// 查询详情
|
||||
async function queryNoticeDetail() {
|
||||
try {
|
||||
SmartLoading.show();
|
||||
const result = await noticeApi.view(route.query.noticeId);
|
||||
noticeDetail.value = result.data;
|
||||
|
||||
noticeViewRecordList.value.onSearch();
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
SmartLoading.hide();
|
||||
}
|
||||
}
|
||||
|
||||
// 点击编辑
|
||||
const noticeFormDrawerRef = ref();
|
||||
function onEdit() {
|
||||
noticeFormDrawerRef.value.showModal(noticeDetail.value.noticeId);
|
||||
}
|
||||
|
||||
// 预览附件
|
||||
const filePreviewRef = ref();
|
||||
function onPrevFile(fileItem) {
|
||||
filePreviewRef.value.showPreview(fileItem);
|
||||
}
|
||||
|
||||
// 打印
|
||||
function print() {
|
||||
let bdhtml = window.document.body.innerHTML;
|
||||
let sprnstr = '<!--startprint-->'; //必须在页面添加<!--startprint-->和<!--endprint-->而且需要打印的内容必须在它们之间
|
||||
let eprnstr = '<!--endprint-->';
|
||||
let prnhtml = bdhtml.substr(bdhtml.indexOf(sprnstr));
|
||||
prnhtml = prnhtml.substring(0, prnhtml.indexOf(eprnstr));
|
||||
let newWin = window.open(''); //新打开一个空窗口
|
||||
newWin.document.body.innerHTML = prnhtml;
|
||||
newWin.document.close(); //在IE浏览器中使用必须添加这一句
|
||||
newWin.focus(); //在IE浏览器中使用必须添加这一句
|
||||
newWin.print(); //打印
|
||||
newWin.close(); //关闭窗口
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.ant-descriptions-item-content) {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.file-list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.file-item {
|
||||
display: block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.visible-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.visible-item {
|
||||
margin-right: 10px;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
.content-header {
|
||||
.content-header-title {
|
||||
margin: 10px 0px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
.content-header-info {
|
||||
margin: 10px 0px;
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
span {
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-html {
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,239 @@
|
||||
<!--
|
||||
* 通知 详情 (员工列表)
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
<template>
|
||||
<a-form class="smart-query-form">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="分类" class="smart-query-form-item">
|
||||
<a-select v-model:value="queryForm.noticeTypeId" style="width: 100px" :showSearch="true" :allowClear="true">
|
||||
<a-select-option v-for="item in noticeTypeList" :key="item.noticeTypeId" :value="item.noticeTypeId">
|
||||
{{ item.noticeTypeName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 300px" v-model:value="queryForm.keywords" placeholder="标题、作者、来源、文号" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="发布时间" class="smart-query-form-item">
|
||||
<a-range-picker v-model:value="publishDate" @change="publishDateChange" style="width: 220px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button-group>
|
||||
<a-button type="primary" @click="onSearch">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="onReload">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false">
|
||||
<a-tabs @change="changeNotViewFlag" size="small">
|
||||
<a-tab-pane :key="0" tab="全部" />
|
||||
<a-tab-pane :key="1" tab="未读" />
|
||||
</a-tabs>
|
||||
|
||||
<a-table
|
||||
rowKey="noticeId"
|
||||
:columns="tableColumns"
|
||||
:dataSource="tableData"
|
||||
:scroll="{ x: 1500 }"
|
||||
:pagination="false"
|
||||
:loading="tableLoading"
|
||||
bordered
|
||||
size="small"
|
||||
>
|
||||
<template #bodyCell="{ column, record, text }">
|
||||
<template v-if="column.dataIndex === 'title'">
|
||||
<span v-show="record.viewFlag">
|
||||
<a @click="toDetail(record.noticeId)" style="color: #666">【{{ record.noticeTypeName }}】{{ text }}(已读)</a>
|
||||
</span>
|
||||
<span v-show="!record.viewFlag">
|
||||
<a @click="toDetail(record.noticeId)"
|
||||
>【{{ record.noticeTypeName }}】{{ text }}
|
||||
<span style="color: red">(未读)</span>
|
||||
</a>
|
||||
</span>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'pageViewCount'"> {{ record.userViewCount }}人 / {{ record.pageViewCount }}次 </template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryNoticeList"
|
||||
@showSizeChange="queryNoticeList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import SmartBooleanSelect from '/@/components/framework/boolean-select/index.vue';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
|
||||
const tableColumns = reactive([
|
||||
{
|
||||
title: `标题`,
|
||||
dataIndex: 'title',
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: `文号`,
|
||||
dataIndex: 'documentNumber',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: `作者`,
|
||||
dataIndex: 'author',
|
||||
width: 40,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: `来源`,
|
||||
dataIndex: 'source',
|
||||
width: 90,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '发布时间',
|
||||
dataIndex: 'publishTime',
|
||||
width: 140,
|
||||
},
|
||||
{
|
||||
title: '用户/页面浏览量',
|
||||
dataIndex: 'pageViewCount',
|
||||
width: 90,
|
||||
},
|
||||
]);
|
||||
|
||||
// ------------------ 通知分类 ------------------
|
||||
|
||||
// 查询分类列表
|
||||
const noticeTypeList = ref([]);
|
||||
async function queryNoticeTypeList() {
|
||||
try {
|
||||
const result = await noticeApi.getAllNoticeTypeList();
|
||||
noticeTypeList.value = result.data;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ 查询相关 ------------------
|
||||
|
||||
const queryFormState = {
|
||||
noticeTypeId: undefined, //分类
|
||||
keywords: '', //标题、作者、来源
|
||||
publishTimeBegin: null, //发布-开始时间
|
||||
publishTimeEnd: null, //发布-截止时间
|
||||
notViewFlag: false, //未读
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
};
|
||||
const queryForm = reactive({ ...queryFormState });
|
||||
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
const tableLoading = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
queryNoticeTypeList();
|
||||
queryNoticeList();
|
||||
});
|
||||
|
||||
function changeNotViewFlag(value) {
|
||||
queryForm.notViewFlag = value === 0 ? null : true;
|
||||
onSearch();
|
||||
}
|
||||
|
||||
// 查询列表
|
||||
async function queryNoticeList() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
const result = await noticeApi.queryEmployeeNotice(queryForm);
|
||||
tableData.value = result.data.list;
|
||||
total.value = result.data.total;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 点击查询
|
||||
function onSearch() {
|
||||
queryForm.pageNum = 1;
|
||||
queryNoticeList();
|
||||
}
|
||||
|
||||
// 点击重置
|
||||
function onReload() {
|
||||
Object.assign(queryForm, queryFormState);
|
||||
publishDate.value = [];
|
||||
createDate.value = [];
|
||||
queryNoticeList();
|
||||
}
|
||||
|
||||
// 发布日期选择
|
||||
const publishDate = ref([]);
|
||||
function publishDateChange(dates, dateStrings) {
|
||||
queryForm.publishTimeBegin = dateStrings[0];
|
||||
queryForm.publishTimeEnd = dateStrings[1];
|
||||
}
|
||||
// 创建日期选择
|
||||
const createDate = ref([]);
|
||||
function createDateChange(dates, dateStrings) {
|
||||
queryForm.createTimeBegin = dateStrings[0];
|
||||
queryForm.createTimeEnd = dateStrings[1];
|
||||
}
|
||||
|
||||
// ------------------ 详情 ------------------
|
||||
|
||||
// 进入详情
|
||||
const router = useRouter();
|
||||
function toDetail(noticeId) {
|
||||
router.push({
|
||||
path: '/oa/notice/notice-employee-detail',
|
||||
query: { noticeId },
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
@@ -0,0 +1,352 @@
|
||||
<!--
|
||||
* 通知 管理列表
|
||||
*
|
||||
* @Author: 1024创新实验室-主任:卓大
|
||||
* @Date: 2022-08-21 19:52:43
|
||||
* @Wechat: zhuda1024
|
||||
* @Email: lab1024@163.com
|
||||
* @Copyright 1024创新实验室 ( https://1024lab.net ),2012-2022
|
||||
-->
|
||||
|
||||
<template>
|
||||
<a-form class="smart-query-form" v-privilege="'notice:query'">
|
||||
<a-row class="smart-query-form-row">
|
||||
<a-form-item label="分类" class="smart-query-form-item">
|
||||
<a-select v-model:value="queryForm.noticeTypeId" style="width: 100px" :showSearch="true" :allowClear="true" placeholder="分类">
|
||||
<a-select-option v-for="item in noticeTypeList" :key="item.noticeTypeId" :value="item.noticeTypeId">
|
||||
{{ item.noticeTypeName }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="关键字" class="smart-query-form-item">
|
||||
<a-input style="width: 300px" v-model:value="queryForm.keywords" placeholder="标题、作者、来源" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="文号" class="smart-query-form-item">
|
||||
<a-input style="width: 150px" v-model:value="queryForm.documentNumber" placeholder="文号" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="创建人" class="smart-query-form-item">
|
||||
<a-input style="width: 100px" v-model:value="queryForm.createUserId" placeholder="创建人" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="是否删除" class="smart-query-form-item">
|
||||
<SmartBooleanSelect v-model:value="queryForm.deletedFlag" style="width: 70px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="发布时间" class="smart-query-form-item">
|
||||
<a-range-picker v-model:value="publishDate" @change="publishDateChange" style="width: 220px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="创建时间" class="smart-query-form-item">
|
||||
<a-range-picker v-model:value="createDate" @change="createDateChange" style="width: 220px" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item class="smart-query-form-item smart-margin-left10">
|
||||
<a-button-group>
|
||||
<a-button type="primary" @click="onSearch">
|
||||
<template #icon>
|
||||
<SearchOutlined />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="onReload">
|
||||
<template #icon>
|
||||
<ReloadOutlined />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-button-group>
|
||||
</a-form-item>
|
||||
</a-row>
|
||||
</a-form>
|
||||
|
||||
<a-card size="small" :bordered="false">
|
||||
<a-row class="smart-table-btn-block">
|
||||
<div class="smart-table-operate-block">
|
||||
<a-button type="primary" size="small" @click="addOrUpdate()" v-privilege="'notice:add'">
|
||||
<template #icon>
|
||||
<PlusOutlined />
|
||||
</template>
|
||||
新建
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="smart-table-setting-block">
|
||||
<TableOperator v-model="tableColumns" :tableId="TABLE_ID_CONST.BUSINESS.OA.NOTICE" :refresh="queryNoticeList" />
|
||||
</div>
|
||||
</a-row>
|
||||
|
||||
<a-table
|
||||
rowKey="noticeId"
|
||||
:columns="tableColumns"
|
||||
:dataSource="tableData"
|
||||
:scroll="{ x: 1510 }"
|
||||
:pagination="false"
|
||||
:loading="tableLoading"
|
||||
size="small"
|
||||
bordered
|
||||
>
|
||||
<template #bodyCell="{ column, record, text }">
|
||||
<template v-if="column.dataIndex === 'title'">
|
||||
<a @click="toDetail(record.noticeId)">{{ text }}</a>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'allVisibleFlag'"> {{ text ? '全部可见' : '部分可见' }} </template>
|
||||
<template v-else-if="column.dataIndex === 'publishFlag'">
|
||||
{{ text ? '已发布' : '待发布' }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'deletedFlag'">
|
||||
<a-tag v-show="text" color="error">已删除</a-tag>
|
||||
<a-tag v-show="!text" color="success">未删除</a-tag>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'action'">
|
||||
<div class="smart-table-operate">
|
||||
<a-button type="link" @click="addOrUpdate(record.noticeId)" v-privilege="'notice:edit'">编辑</a-button>
|
||||
<a-button type="link" @click="onDelete(record.noticeId)" v-privilege="'notice:delete'" danger>删除</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
|
||||
<div class="smart-query-table-page">
|
||||
<a-pagination
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
show-less-items
|
||||
:pageSizeOptions="PAGE_SIZE_OPTIONS"
|
||||
:defaultPageSize="queryForm.pageSize"
|
||||
v-model:current="queryForm.pageNum"
|
||||
v-model:pageSize="queryForm.pageSize"
|
||||
:total="total"
|
||||
@change="queryNoticeList"
|
||||
@showSizeChange="queryNoticeList"
|
||||
:show-total="(total) => `共${total}条`"
|
||||
/>
|
||||
</div>
|
||||
</a-card>
|
||||
|
||||
<NoticeFormDrawer ref="noticeFormDrawer" @reloadList="queryNoticeList" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { PAGE_SIZE, PAGE_SIZE_OPTIONS } from '/@/constants/common-const';
|
||||
import SmartBooleanSelect from '/@/components/framework/boolean-select/index.vue';
|
||||
import { noticeApi } from '/@/api/business/oa/notice-api';
|
||||
import NoticeFormDrawer from './components/notice-form-drawer.vue';
|
||||
import { smartSentry } from '/@/lib/smart-sentry';
|
||||
import TableOperator from '/@/components/support/table-operator/index.vue';
|
||||
import { TABLE_ID_CONST } from '/@/constants/support/table-id-const';
|
||||
|
||||
|
||||
const queryFormState = {
|
||||
noticeTypeId: undefined, //分类
|
||||
keywords: '', //标题、作者、来源
|
||||
documentNumber: '', //文号
|
||||
createUserId: undefined, //创建人
|
||||
deletedFlag: undefined, //删除标识
|
||||
createTimeBegin: null, //创建-开始时间
|
||||
createTimeEnd: null, //创建-截止时间
|
||||
publishTimeBegin: null, //发布-开始时间
|
||||
publishTimeEnd: null, //发布-截止时间
|
||||
pageNum: 1,
|
||||
pageSize: PAGE_SIZE,
|
||||
};
|
||||
const queryForm = reactive({ ...queryFormState });
|
||||
|
||||
const tableColumns = ref([
|
||||
{
|
||||
title: `标题`,
|
||||
dataIndex: 'title',
|
||||
width: 300,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: `文号`,
|
||||
dataIndex: 'documentNumber',
|
||||
width: 100,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '分类',
|
||||
dataIndex: 'noticeTypeName',
|
||||
width: 60,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: `作者`,
|
||||
dataIndex: 'author',
|
||||
width: 80,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: `来源`,
|
||||
dataIndex: 'source',
|
||||
width: 90,
|
||||
ellipsis: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: '可见范围',
|
||||
dataIndex: 'allVisibleFlag',
|
||||
width: 90,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '发布',
|
||||
dataIndex: 'publishFlag',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '删除',
|
||||
dataIndex: 'deletedFlag',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '发布时间',
|
||||
dataIndex: 'publishTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '页面浏览量',
|
||||
dataIndex: 'pageViewCount',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
title: '用户浏览量',
|
||||
dataIndex: 'userViewCount',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'createUserName',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createTime',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
fixed: 'right',
|
||||
width: 90,
|
||||
},
|
||||
]);
|
||||
|
||||
// ------------------ 通知分类 ------------------
|
||||
|
||||
// 查询分类列表
|
||||
const noticeTypeList = ref([]);
|
||||
async function queryNoticeTypeList() {
|
||||
try {
|
||||
const result = await noticeApi.getAllNoticeTypeList();
|
||||
noticeTypeList.value = result.data;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ 查询相关 ------------------
|
||||
|
||||
const tableData = ref([]);
|
||||
const total = ref(0);
|
||||
const tableLoading = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
queryNoticeTypeList();
|
||||
queryNoticeList();
|
||||
});
|
||||
|
||||
// 查询列表
|
||||
async function queryNoticeList() {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
const result = await noticeApi.queryNotice(queryForm);
|
||||
tableData.value = result.data.list;
|
||||
total.value = result.data.total;
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 点击查询
|
||||
function onSearch() {
|
||||
queryForm.pageNum = 1;
|
||||
queryNoticeList();
|
||||
}
|
||||
|
||||
// 点击重置
|
||||
function onReload() {
|
||||
Object.assign(queryForm, queryFormState);
|
||||
publishDate.value = [];
|
||||
createDate.value = [];
|
||||
queryNoticeList();
|
||||
}
|
||||
|
||||
// 发布日期选择
|
||||
const publishDate = ref([]);
|
||||
function publishDateChange(dates, dateStrings) {
|
||||
queryForm.publishTimeBegin = dateStrings[0];
|
||||
queryForm.publishTimeEnd = dateStrings[1];
|
||||
}
|
||||
// 创建日期选择
|
||||
const createDate = ref([]);
|
||||
function createDateChange(dates, dateStrings) {
|
||||
queryForm.createTimeBegin = dateStrings[0];
|
||||
queryForm.createTimeEnd = dateStrings[1];
|
||||
}
|
||||
|
||||
// ------------------ 新建、编辑 ------------------
|
||||
|
||||
// 新建、编辑
|
||||
const noticeFormDrawer = ref();
|
||||
function addOrUpdate(noticeId) {
|
||||
noticeFormDrawer.value.showModal(noticeId);
|
||||
}
|
||||
|
||||
// ------------------ 删除 ------------------
|
||||
|
||||
// 删除
|
||||
function onDelete(noticeId) {
|
||||
Modal.confirm({
|
||||
title: '提示',
|
||||
content: '确认删除此数据吗?',
|
||||
onOk() {
|
||||
deleteNotice(noticeId);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 删除API
|
||||
async function deleteNotice(noticeId) {
|
||||
try {
|
||||
tableLoading.value = true;
|
||||
await noticeApi.deleteNotice(noticeId);
|
||||
message.success('删除成功');
|
||||
queryNoticeList();
|
||||
} catch (err) {
|
||||
smartSentry.captureError(err);
|
||||
} finally {
|
||||
tableLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ 详情 ------------------
|
||||
|
||||
// 进入详情
|
||||
const router = useRouter();
|
||||
function toDetail(noticeId) {
|
||||
router.push({
|
||||
path: '/oa/notice/notice-detail',
|
||||
query: { noticeId },
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
Reference in New Issue
Block a user