Commit ece0be8a authored by jiaxu.yan's avatar jiaxu.yan

feat : 框架搭建

parent 14c08d70
# spa-title
VITE_GLOB_APP_TITLE = Vben Admin
VITE_GLOB_APP_TITLE = '海泰工程管理'
import { ProjectParams, ProjectListGetResultModel, ProjectModel } from './model/biddingPlanModel';
import { defHttp } from '@/utils/http/axios';
enum Api {
GetList = '/mgapi/project/project/list/page',
AddProject = '/mgapi/project/projectManage/add',
UpdateProject = '/mgapi/project/projectManage/update',
}
export const getListByPage = (params?: ProjectParams) =>
defHttp.post<ProjectListGetResultModel>({ url: Api.GetList, data: params });
export const addItem = (params?: any) =>
defHttp.post<ProjectModel>({ url: Api.AddProject, data: params });
export const updateItem = (params?: any) =>
defHttp.post<ProjectModel>({ url: Api.UpdateProject, data: params });
import { BasicPageParams } from '@/api/model/baseModel';
export type ProjectParams = {
projectName?: string;
};
export type ProjectPageParams = BasicPageParams & ProjectParams;
export interface ProjectListItem {
id: string;
project_name: string;
is_reserve_projecte: string;
construction_site: string;
construction_mode: string;
project_type: string;
project_overview: string;
construction_purpose: string;
del_flag: string;
construction_scale: string;
funding_source: string;
implementing_entity: string;
logo: string;
create_time: null;
create_by: string;
update_time: null;
update_by: string;
}
export interface ProjectModel {
id?: string | number;
constructionMode: string;
isReserveProject: string;
projectType: string;
projectOverview: string;
constructionPurpose: string;
}
export type ProjectListGetResultModel = ProjectListItem[];
......@@ -2,15 +2,15 @@ import { ProjectParams, ProjectListGetResultModel, ProjectModel } from './model/
import { defHttp } from '@/utils/http/axios';
enum Api {
GetAllProjectList = '/mgapi/project/project/list/page',
GetList = '/mgapi/project/project/list/page',
AddProject = '/mgapi/project/projectManage/add',
UpdateProject = '/mgapi/project/projectManage/update',
}
export const getProjectListByPage = (params?: ProjectParams) =>
defHttp.post<ProjectListGetResultModel>({ url: Api.GetAllProjectList, data: params });
export const getListByPage = (params?: ProjectParams) =>
defHttp.post<ProjectListGetResultModel>({ url: Api.GetList, data: params });
export const addProjectItem = (params?: any) =>
export const addItem = (params?: any) =>
defHttp.post<ProjectModel>({ url: Api.AddProject, data: params });
export const updateProjectItem = (params?: any) =>
export const updateItem = (params?: any) =>
defHttp.post<ProjectModel>({ url: Api.UpdateProject, data: params });
<template>
<div class="page-card">
<div class="page-card-title"> {{ title }}</div>
<div class="page-card-body">
<slot></slot>
</div>
</div>
</template>
<script lang="ts" setup>
import { string } from 'vue-types';
const props = defineProps({
title: string | undefined,
});
</script>
<style lang="less">
.page-card {
background: #ffffff;
border-radius: 4px;
padding: 0 8px;
margin-bottom: 16px;
.page-card-title {
height: 35px;
padding: 10px 0;
border-bottom: 1px solid #f0f0f0;
display: flex;
align-items: center;
justify-content: flex-start;
&::before {
content: ' ';
display: block;
width: 4px;
height: 12px;
background: #166acb;
margin-right: 8px;
}
}
.page-card-body {
padding: 24px;
}
}
</style>
<template>
<div ref="wrapRef" :class="getWrapperClass">
<div class="page-card">
<div class="page-card-title"> {{ title }}</div>
<div class="page-card-body">
<BasicForm
ref="formRef"
submitOnReset
v-bind="getFormProps"
v-if="getBindValues.useSearchForm"
:tableAction="tableAction"
@register="registerForm"
@submit="handleSearchInfoChange"
@advanced-change="redoHeight"
>
<template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</BasicForm>
<div class="toolbar">
<slot name="toolbar"></slot>
</div>
<Table
ref="tableElRef"
v-bind="getBindValues"
:rowClassName="getRowClassName"
v-show="getEmptyDataIsShowTable"
@change="handleTableChange"
@resize-column="setColumnWidth"
@expand="handleTableExpand"
>
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
<slot :name="item" v-bind="data || {}"></slot>
</template>
<template #headerCell="{ column }">
<slot name="headerCell" v-bind="{ column }">
<HeaderCell :column="column" />
</slot>
</template>
<template #bodyCell="data">
<slot name="bodyCell" v-bind="data || {}"></slot>
</template>
</Table>
<PageCard :title="title">
<BasicForm
ref="formRef"
submitOnReset
v-bind="getFormProps"
v-if="getBindValues.useSearchForm"
:tableAction="tableAction"
@register="registerForm"
@submit="handleSearchInfoChange"
@advanced-change="redoHeight"
>
<template #[replaceFormSlotKey(item)]="data" v-for="item in getFormSlotKeys">
<slot :name="item" v-bind="data || {}"></slot>
</template>
</BasicForm>
<div class="toolbar">
<slot name="toolbar"></slot>
</div>
</div>
<Table
ref="tableElRef"
v-bind="getBindValues"
:rowClassName="getRowClassName"
v-show="getEmptyDataIsShowTable"
@change="handleTableChange"
@resize-column="setColumnWidth"
@expand="handleTableExpand"
>
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
<slot :name="item" v-bind="data || {}"></slot>
</template>
<template #headerCell="{ column }">
<slot name="headerCell" v-bind="{ column }">
<HeaderCell :column="column" />
</slot>
</template>
<template #bodyCell="data">
<slot name="bodyCell" v-bind="data || {}"></slot>
</template>
</Table>
</PageCard>
</div>
</template>
<script lang="ts" setup>
......@@ -77,7 +74,7 @@
import { useElementSize } from '@vueuse/core';
import { basicProps } from './props';
import { isFunction } from '@/utils/is';
import PageCard from '@/components/Page/src/PageCard.vue';
defineOptions({ name: 'BasicTable' });
const props = defineProps(basicProps);
......@@ -230,6 +227,7 @@
const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } =
useTableForm(getProps, slots, fetch, getLoading);
console.log(getFormProps);
const getBindValues = computed(() => {
const dataSource = unref(getDataSourceRef);
......
......@@ -19,7 +19,7 @@ const dashboard: AppRouteModule = {
name: 'dashboard',
component: () => import('@/views/dashboard/analysis/index.vue'),
meta: {
// affix: true,
affix: true,
title: '门户页',
orderNo: 0,
},
......
......@@ -106,7 +106,6 @@ export const useUserStore = defineStore({
},
async afterLoginAction(goHome?: boolean): Promise<GetUserInfoModel | null> {
// if (!this.getToken) return null;
console.log(22);
// get user info
const userInfo = await this.getUserInfoAction();
const sessionTimeout = this.sessionTimeout;
......@@ -132,7 +131,6 @@ export const useUserStore = defineStore({
async getUserInfoAction(): Promise<UserInfo | null> {
// if (!this.getToken) return null;
const userInfo = await getUserInfo();
console.log(111);
// if (isArray(roles)) {
// const roleList = roles.map((item) => item.value) as RoleEnum[];
// this.setRoleList(roleList);
......
<template>
<BasicDrawer
v-bind="$attrs"
@register="registerDrawer"
showFooter
:title="getTitle"
width="500px"
@ok="handleSubmit"
>
<BasicForm @register="registerForm">
<template #menu="{ model, field }">
<BasicTree
v-model:value="model[field]"
:treeData="treeData"
:fieldNames="{ title: 'menuName', key: 'id' }"
checkable
toolbar
title="菜单分配"
/>
</template>
</BasicForm>
</BasicDrawer>
</template>
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicForm, useForm } from '@/components/Form';
import { formSchema } from './role.data';
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
import { BasicTree, TreeItem } from '@/components/Tree';
import { getMenuList } from '@/api/demo/system';
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
const treeData = ref<TreeItem[]>([]);
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 90,
baseColProps: { span: 24 },
schemas: formSchema,
showActionButtonGroup: false,
});
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => {
resetFields();
setDrawerProps({ confirmLoading: false });
// 需要在setFieldsValue之前先填充treeData,否则Tree组件可能会报key not exist警告
if (unref(treeData).length === 0) {
treeData.value = (await getMenuList()) as any as TreeItem[];
}
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
setFieldsValue({
...data.record,
});
}
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色'));
async function handleSubmit() {
try {
const values = await validate();
setDrawerProps({ confirmLoading: true });
// TODO custom api
console.log(values);
closeDrawer();
emit('success');
} finally {
setDrawerProps({ confirmLoading: false });
}
}
</script>
......@@ -15,9 +15,9 @@
<script lang="ts" setup>
import { ref, computed, unref } from 'vue';
import { BasicForm, useForm } from '@/components/Form';
import { formSchema } from './project.data';
import { formSchema } from './biddingPlan.data';
import { BasicDrawer, useDrawerInner } from '@/components/Drawer';
import { addProjectItem, updateProjectItem } from '@/api/project/project';
import { addItem, updateItem } from '@/api/project/biddingPlan';
import { is } from '@/utils/is';
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
......@@ -49,7 +49,7 @@
setDrawerProps({ confirmLoading: true });
// TODO custom api
console.log(values);
let res = isUpdate.value ? await updateProjectItem(values) : await addProjectItem(values);
let res = isUpdate.value ? await updateItem(values) : await addItem(values);
console.log(res);
closeDrawer();
......
<template>
<div>
<BasicTable @register="registerTable">
<BasicTable @register="registerTable" :title="'招标计划'">
<template #toolbar>
<a-button type="primary" @click="handleCreate"> 新增角色 </a-button>
<a-button type="primary" icon="" @click="handleCreate"> 新增招标计划 </a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
......@@ -26,31 +26,30 @@
</template>
</template>
</BasicTable>
<RoleDrawer @register="registerDrawer" @success="handleSuccess" />
<biddingPlanDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
</template>
<script lang="ts" setup>
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getRoleListByPage } from '@/api/demo/system';
import { getListByPage } from '@/api/project/biddingPlan';
import { useDrawer } from '@/components/Drawer';
import RoleDrawer from './RoleDrawer.vue';
import biddingPlanDrawer from './biddingPlanDrawer.vue';
import { columns, searchFormSchema } from './role.data';
import { columns, searchFormSchema } from './biddingPlan.data';
defineOptions({ name: 'RoleManagement' });
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload }] = useTable({
title: '角色列表',
api: getRoleListByPage,
api: getListByPage,
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
useSearchForm: true,
showTableSetting: true,
showTableSetting: false,
bordered: true,
showIndexColumn: false,
actionColumn: {
......
import { BasicColumn, FormSchema } from '@/components/Table';
import { h } from 'vue';
import { Switch } from 'ant-design-vue';
import { setRoleStatus } from '@/api/demo/system';
import { useMessage } from '@/hooks/web/useMessage';
type CheckedType = boolean | string | number;
export const columns: BasicColumn[] = [
{
title: '角色名称',
dataIndex: 'roleName',
width: 200,
},
{
title: '角色值',
dataIndex: 'roleValue',
width: 180,
},
{
title: '排序',
dataIndex: 'orderNo',
width: 50,
},
{
title: '状态',
dataIndex: 'status',
width: 120,
customRender: ({ record }) => {
if (!Reflect.has(record, 'pendingStatus')) {
record.pendingStatus = false;
}
return h(Switch, {
checked: record.status === '1',
checkedChildren: '停用',
unCheckedChildren: '启用',
loading: record.pendingStatus,
onChange(checked: CheckedType) {
record.pendingStatus = true;
const newStatus = checked ? '1' : '0';
const { createMessage } = useMessage();
setRoleStatus(record.id, newStatus)
.then(() => {
record.status = newStatus;
createMessage.success(`已成功修改角色状态`);
})
.catch(() => {
createMessage.error('修改角色状态失败');
})
.finally(() => {
record.pendingStatus = false;
});
},
});
},
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 180,
},
{
title: '备注',
dataIndex: 'remark',
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'roleNme',
label: '角色名称',
component: 'Input',
colProps: { span: 8 },
},
{
field: 'status',
label: '状态',
component: 'Select',
componentProps: {
options: [
{ label: '启用', value: '1' },
{ label: '停用', value: '0' },
],
},
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'roleName',
label: '角色名称',
required: true,
component: 'Input',
},
{
field: 'roleValue',
label: '角色值',
required: true,
component: 'Input',
},
{
field: 'status',
label: '状态',
component: 'RadioButtonGroup',
defaultValue: '0',
componentProps: {
options: [
{ label: '启用', value: '1' },
{ label: '停用', value: '0' },
],
},
},
{
label: '备注',
field: 'remark',
component: 'InputTextArea',
},
{
label: ' ',
field: 'menu',
slot: 'menu',
},
];
export const cardList = (() => {
const result: any[] = [];
for (let i = 0; i < 6; i++) {
result.push({
id: i,
title: 'Vben Admin',
description: '基于Vue Next, TypeScript, Ant Design Vue实现的一套完整的企业级后台管理系统',
datetime: '2020-11-26 17:39',
extra: '编辑',
icon: 'logos:vue',
color: '#1890ff',
author: 'Vben',
percent: 20 * (i + 1),
});
}
return result;
})();
<template>
<div>
<BasicTable @register="registerTable" :title="'房产档案列表'">
<template #toolbar>
<a-button type="primary" @click="handleCreate"> 新增项目 </a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
icon: 'clarity:note-edit-line',
onClick: handleEdit.bind(null, record),
},
{
icon: 'ant-design:delete-outlined',
color: 'error',
popConfirm: {
title: '是否确认删除',
placement: 'left',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</template>
</BasicTable>
<ProjectDrawer @register="registerDrawer" @success="handleSuccess" />
</div>
<PageWrapper :class="prefixCls">
<PageCard title="数据简报">
<div :class="`${prefixCls}__top`">
<Row :gutter="12">
<Col :span="8" :class="`${prefixCls}__top-col`">
<div>我的待办</div>
<p>8个任务</p>
</Col>
<Col :span="8" :class="`${prefixCls}__top-col`">
<div>本周任务平均处理时间</div>
<p>32分钟</p>
</Col>
<Col :span="8" :class="`${prefixCls}__top-col`">
<div>本周完成任务数</div>
<p>24个任务</p>
</Col>
</Row>
</div>
</PageCard>
<PageCard title="项目列表">
<div :class="`${prefixCls}__content`">
<BasicForm submitOnReset @register="register" @submit="handleSearchInfoChange" />
<List :pagination="pagination">
<template v-for="item in cardList" :key="item.id">
<List.Item class="list">
<List.Item.Meta>
<template #avatar>
<Icon class="icon" v-if="item.icon" :icon="item.icon" :color="item.color" />
</template>
<template #title>
<span>{{ item.title }}</span>
<div class="extra" v-if="item.extra">
{{ item.extra }}
</div>
</template>
<template #description>
<div class="description">
{{ item.description }}
</div>
<div class="info">
<div><span>Owner</span>{{ item.author }}</div>
<div><span>开始时间</span>{{ item.datetime }}</div>
</div>
<div class="progress">
<Progress :percent="item.percent" status="active" />
</div>
</template>
</List.Item.Meta>
</List.Item>
</template>
</List>
</div>
</PageCard>
</PageWrapper>
</template>
<script lang="ts" setup>
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getProjectListByPage } from '@/api/project/project';
import { useDrawer } from '@/components/Drawer';
import ProjectDrawer from './ProjectDrawer.vue';
import { columns, searchFormSchema } from './project.data';
defineOptions({ name: 'RoleManagement' });
const [registerDrawer, { openDrawer }] = useDrawer();
const [registerTable, { reload }] = useTable({
api: getProjectListByPage,
title: '123',
columns,
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
import { Progress, Row, Col, List } from 'ant-design-vue';
import Icon from '@/components/Icon/Icon.vue';
import { cardList } from './data';
import { PageWrapper } from '@/components/Page';
import PageCard from '@/components/Page/src/PageCard.vue';
import { BasicForm, FormSchema, useForm } from '@/components/Form';
import { unref, computed } from 'vue';
import type { FormProps } from '@/components/Form';
const schemas: FormSchema[] = [
{
field: 'ProjecName',
label: '',
component: 'Input',
componentProps: {
placeholder: '点击选择图标',
},
colProps: { span: 4 },
},
useSearchForm: true,
showTableSetting: false,
bordered: true,
showIndexColumn: false,
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
// slots: { customRender: 'action' },
fixed: undefined,
{
field: 'ProjecName',
label: '',
component: 'Input',
componentProps: {
placeholder: '点击选择图标',
},
colProps: { span: 4 },
},
];
const [register] = useForm({
schemas,
});
const prefixCls = 'list-basic';
function handleCreate() {
openDrawer(true, {
isUpdate: false,
});
const pagination = {
show: true,
pageSize: 3,
};
function handleSearchInfoChange(info: Recordable) {
console.log(info);
}
const getFormProps = computed((): Partial<FormProps> => {
const { formConfig } = unref(propsRef);
const { submitButtonOptions } = formConfig || {};
return {
showAdvancedButton: true,
...formConfig,
submitButtonOptions: { loading: unref(getLoading), ...submitButtonOptions },
compact: true,
};
});
</script>
<style lang="less" scoped>
.list-basic {
&__top {
padding: 24px;
background-color: @component-background;
text-align: center;
function handleEdit(record: Recordable) {
openDrawer(true, {
record,
isUpdate: true,
});
}
&-col {
&:not(:last-child) {
border-right: 1px dashed @border-color-base;
}
function handleDelete(record: Recordable) {
console.log(record);
}
div {
margin-bottom: 12px;
color: @text-color-base;
font-size: 14px;
line-height: 22px;
}
p {
margin: 0;
color: @text-color-base;
font-size: 24px;
line-height: 32px;
}
}
}
function handleSuccess() {
reload();
&__content {
background-color: @component-background;
.list {
position: relative;
}
.icon {
font-size: 40px !important;
}
.extra {
position: absolute;
top: 20px;
right: 15px;
color: @primary-color;
font-weight: normal;
cursor: pointer;
}
.description {
display: inline-block;
width: 40%;
}
.info {
display: inline-block;
width: 30%;
text-align: center;
div {
display: inline-block;
padding: 0 20px;
span {
display: block;
}
}
}
.progress {
display: inline-block;
width: 15%;
vertical-align: top;
}
}
}
</script>
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment