開発ガイド
BaiZe Frameworkで開発を始めるための完全ガイド
5. Vue3機能開発
1. 機能開発の基本フロー
フロントエンドでの機能開発は、以下の手順で進めます:
1
APIモジュール作成
src/api/配下にAPIインターフェースモジュールを作成します。
2
定数・列挙定義
必要に応じて定数や列挙をsrc/constants/に定義します。
3
ページコンポーネント作成
src/views/配下にVueコンポーネントを作成します。
4
メニュー設定
バックエンドでメニューを登録し、コンポーネントパスを設定します。
2. APIモジュールの作成
APIモジュールはsrc/api/に領域別に配置します。
// src/api/system/employee-api.js
import { getRequest, postRequest } from '/@/lib/axios';
export const employeeApi = {
/**
* 従業員一覧取得
*/
query: (params) => postRequest('/api/employee/query', params),
/**
* 従業員追加
*/
add: (data) => postRequest('/api/employee/add', data),
/**
* 従業員更新
*/
update: (data) => postRequest('/api/employee/update', data),
/**
* 従業員削除
*/
delete: (employeeId) => postRequest('/api/employee/delete', { employeeId }),
/**
* 従業員詳細取得
*/
getDetail: (employeeId) => getRequest(`/api/employee/detail/${employeeId}`),
};
3. ページコンポーネントの基本構造
Vue 3 Composition API(<script setup>)を使用したページコンポーネントの基本構造です。
<template>
<div class="employee-page">
<!-- 検索フォーム -->
<a-card :bordered="false">
<a-form layout="inline">
<a-form-item label="従業員名">
<a-input v-model:value="queryForm.employeeName" placeholder="従業員名を入力" />
</a-form-item>
<a-form-item label="部門">
<department-select v-model:value="queryForm.departmentId" />
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="queryData">検索</a-button>
<a-button @click="resetQuery">リセット</a-button>
</a-space>
</a-form-item>
</a-form>
</a-card>
<!-- データテーブル -->
<a-card :bordered="false" style="margin-top: 16px">
<template #title>
<a-space>
<a-button
v-privilege="'employee:add'"
type="primary"
@click="openAddModal"
>
追加
</a-button>
<a-button @click="queryData">更新</a-button>
</a-space>
</template>
<a-table
:columns="columns"
:data-source="dataSource"
:loading="loading"
:pagination="pagination"
@change="handleTableChange"
row-key="employeeId"
>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'action'">
<table-operator
:row-id="record.employeeId"
:delete-permission="'employee:delete'"
@edit="openEditModal"
@delete="deleteEmployee"
/>
</template>
</template>
</a-table>
</a-card>
<!-- 追加・編集モーダル -->
<employee-modal
v-model:visible="modalVisible"
:employee-id="selectedEmployeeId"
@success="queryData"
/>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { message, Modal } from 'ant-design-vue';
import { employeeApi } from '/@/api/system/employee-api';
import DepartmentSelect from '/@/components/system/department-select/index.vue';
import TableOperator from '/@/components/support/table-operator/index.vue';
import EmployeeModal from './components/employee-modal.vue';
// 検索フォーム
const queryForm = reactive({
employeeName: '',
departmentId: undefined,
});
// テーブルデータ
const dataSource = ref([]);
const loading = ref(false);
// ページネーション
const pagination = reactive({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showTotal: (total) => `合計 ${total} 件`,
});
// テーブル列定義
const columns = [
{ title: '従業員ID', dataIndex: 'employeeId', width: 100 },
{ title: '従業員名', dataIndex: 'employeeName' },
{ title: '部門', dataIndex: 'departmentName' },
{ title: '作成日時', dataIndex: 'createTime', width: 180 },
{ title: '操作', dataIndex: 'action', width: 150, fixed: 'right' },
];
// モーダル
const modalVisible = ref(false);
const selectedEmployeeId = ref(null);
/**
* データ検索
*/
const queryData = async () => {
loading.value = true;
try {
const res = await employeeApi.query({
...queryForm,
pageNum: pagination.current,
pageSize: pagination.pageSize,
});
dataSource.value = res.data.dataList;
pagination.total = res.data.totalCount;
} catch (e) {
message.error('データ取得に失敗しました');
} finally {
loading.value = false;
}
};
/**
* 検索リセット
*/
const resetQuery = () => {
queryForm.employeeName = '';
queryForm.departmentId = undefined;
pagination.current = 1;
queryData();
};
/**
* テーブル変更イベント
*/
const handleTableChange = (pag) => {
pagination.current = pag.current;
pagination.pageSize = pag.pageSize;
queryData();
};
/**
* 追加モーダルを開く
*/
const openAddModal = () => {
selectedEmployeeId.value = null;
modalVisible.value = true;
};
/**
* 編集モーダルを開く
*/
const openEditModal = (employeeId) => {
selectedEmployeeId.value = employeeId;
modalVisible.value = true;
};
/**
* 従業員削除
*/
const deleteEmployee = (employeeId) => {
Modal.confirm({
title: '確認',
content: 'この従業員を削除してもよろしいですか?',
onOk: async () => {
try {
await employeeApi.delete(employeeId);
message.success('削除しました');
queryData();
} catch (e) {
message.error('削除に失敗しました');
}
},
});
};
// 初期化
onMounted(() => {
queryData();
});
</script>
<style lang="less" scoped>
.employee-page {
padding: 16px;
}
</style>
4. スマートコンポーネントの使用
BaiZe Frameworkには多くの再利用可能なスマートコンポーネントが用意されています。
4.1 部門セレクター
<department-select v-model:value="form.departmentId" />
4.2 従業員セレクター
<employee-select v-model:value="form.employeeId" />
4.3 辞書セレクター
<dict-select v-model:value="form.status" dict-type="employee_status" />
4.4 テーブル操作
<table-operator
:row-id="record.id"
:edit-permission="'employee:update'"
:delete-permission="'employee:delete'"
@edit="openEditModal"
@delete="deleteItem"
/>
4.5 ファイルアップロード
<file-upload
v-model:value="form.fileId"
:max-count="1"
list-type="picture-card"
/>
5. 権限の使用
5.1 ディレクティブによる権限制御
<a-button v-privilege="'employee:add'">追加</a-button>
5.2 プログラム的権限チェック
import { useUserStore } from '/@/store/modules/user';
const userStore = useUserStore();
if (userStore.hasPermission('employee:add')) {
// 権限がある場合の処理
}
6. 定数・列挙の使用
import { FLAG_NUMBER_ENUM, GENDER_ENUM } from '/@/constants/common-const';
// 使用
if (form.status === FLAG_NUMBER_ENUM.YES) {
// 有効ステータス
}
const genderOptions = Object.keys(GENDER_ENUM).map(key => ({
label: GENDER_ENUM[key],
value: key,
}));
7. 開発時の注意事項
7.1 パスエイリアス
- /@/ は src/ にマッピングされます
- 一貫性を保つため/@/を使用してインポートします
7.2 コンポーネント命名
- indexコンポーネントを除き、複数語のコンポーネント名が必要です
- ルートcomponentNameはメニューmenuIdと一致させる必要があります(keep-alive動作のため)
- キャッシュ互換のため、ルートガードでコンポーネントが動的にリネームされます
7.3 スタイル
- Lessプリプロセッサ、カスタム変数は src/theme/custom-variables.js
- Ant DesignテーマカスタマイズはmodifyVars経由
- 主色调:#1677ff(設定可能)
7.4 ESLint & Prettier
- ESLint拡張:plugin:vue/vue3-essential、eslint:recommended
- Prettier:150文字行幅、シングルクォート、セミコロン、2スペースインデント
- Vueコンポーネント複数語名称強制(indexは例外)