This commit is contained in:
Joe
2026-01-16 15:49:34 +08:00
commit 550d3e1f42
380 changed files with 62024 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
import request from '../utils/request'
export function get<<.ModelName>>List(params) {
return request({
url: '/<<.ModuleName>>s',
method: 'get',
params
})
}
export function get<<.ModelName>>Detail(id) {
return request({
url: `/<<.ModuleName>>s/${id}`,
method: 'get'
})
}
<<if .HasCreate>>
export function create<<.ModelName>>(data) {
return request({
url: '/<<.ModuleName>>s',
method: 'post',
data
})
}
<<end>>
<<if .HasEdit>>
export function update<<.ModelName>>(id, data) {
return request({
url: `/<<.ModuleName>>s/${id}`,
method: 'put',
data
})
}
<<end>>
<<if .HasDelete>>
export function delete<<.ModelName>>(id) {
return request({
url: `/<<.ModuleName>>s/${id}`,
method: 'delete'
})
}
<<end>>
+143
View File
@@ -0,0 +1,143 @@
package admin
import (
"github.com/goravel/framework/contracts/http"
apperrors "goravel/app/errors"
"goravel/app/http/helpers"
adminrequests "goravel/app/http/requests/admin"
"goravel/app/http/response"
"goravel/app/services"
)
type <<.ControllerName>> struct {
<<.ServiceName>> services.<<.ServiceName>>
}
func New<<.ControllerName>>() *<<.ControllerName>> {
return &<<.ControllerName>>{
<<.ServiceName>>: services.New<<.ServiceName>>(),
}
}
// Index <<.ModelName>>列表
func (c *<<.ControllerName>>) Index(ctx http.Context) http.Response {
page := helpers.GetIntQuery(ctx, "page",1)
pageSize := helpers.GetIntQuery(ctx, "page_size", 10)
<<range .SearchableFields>>
<<.Name>> := ctx.Request().Query("<<.Name>>", "")
<<- end>>
filters := services.<<.ModelName>>Filters{
<<range .SearchableFields>>
<<.PascalName>>: <<.Name>>,
<<- end>>
}
list, total, err := c.<<.ServiceName>>.GetList(filters, page, pageSize)
if err != nil {
if businessErr, ok := apperrors.GetBusinessError(err); ok {
return response.Error(ctx, http.StatusInternalServerError, businessErr.Code)
}
return response.Error(ctx, http.StatusInternalServerError, err.Error())
}
return response.Success(ctx, http.Json{
"list": list,
"total": total,
"page": page,
"page_size": pageSize,
})
}
// Show <<.ModelName>>详情
func (c *<<.ControllerName>>) Show(ctx http.Context) http.Response {
id := helpers.GetUintRoute(ctx, "id")
item, err := c.<<.ServiceName>>.GetByID(id)
if err != nil {
if businessErr, ok := apperrors.GetBusinessError(err); ok {
return response.Error(ctx, http.StatusNotFound, businessErr.Code)
}
return response.Error(ctx, http.StatusNotFound, err.Error())
}
return response.Success(ctx, http.Json{
"<<.ModuleName>>": item,
})
}
// Store 创建<<.ModelName>>
func (c *<<.ControllerName>>) Store(ctx http.Context) http.Response {
<<if .HasCreate>>
var req adminrequests.<<.RequestCreateName>>
errors, err := ctx.Request().ValidateRequest(&req)
if err != nil {
return response.Error(ctx, http.StatusBadRequest, err.Error())
}
if errors != nil {
return response.ValidationError(ctx, http.StatusBadRequest, "validation_failed", errors.All())
}
item, err := c.<<.ServiceName>>.Create(&req)
if err != nil {
if businessErr, ok := apperrors.GetBusinessError(err); ok {
return response.Error(ctx, http.StatusInternalServerError, businessErr.Code)
}
return response.Error(ctx, http.StatusInternalServerError, err.Error())
}
return response.Success(ctx, http.Json{
"<<.ModuleName>>": item,
})
<<else>>
return response.Error(ctx, http.StatusForbidden, "create_not_allowed")
<<end>>
}
// Update 更新<<.ModelName>>
func (c *<<.ControllerName>>) Update(ctx http.Context) http.Response {
<<if .HasEdit>>
id := helpers.GetUintRoute(ctx, "id")
var req adminrequests.<<.RequestUpdateName>>
errors, err := ctx.Request().ValidateRequest(&req)
if err != nil {
return response.Error(ctx, http.StatusBadRequest, err.Error())
}
if errors != nil {
return response.ValidationError(ctx, http.StatusBadRequest, "validation_failed", errors.All())
}
item, err := c.<<.ServiceName>>.Update(id, &req)
if err != nil {
if businessErr, ok := apperrors.GetBusinessError(err); ok {
return response.Error(ctx, http.StatusInternalServerError, businessErr.Code)
}
return response.Error(ctx, http.StatusInternalServerError, err.Error())
}
return response.Success(ctx, http.Json{
"<<.ModuleName>>": item,
})
<<else>>
return response.Error(ctx, http.StatusForbidden, "update_not_allowed")
<<end>>
}
// Destroy 删除<<.ModelName>>
func (c *<<.ControllerName>>) Destroy(ctx http.Context) http.Response {
<<if .HasDelete>>
id := helpers.GetUintRoute(ctx, "id")
if err := c.<<.ServiceName>>.Delete(id); err != nil {
if businessErr, ok := apperrors.GetBusinessError(err); ok {
return response.Error(ctx, http.StatusInternalServerError, businessErr.Code)
}
return response.Error(ctx, http.StatusInternalServerError, err.Error())
}
return response.Success(ctx, "delete_success", http.Json{})
<<else>>
return response.Error(ctx, http.StatusForbidden, "delete_not_allowed")
<<end>>
}
+264
View File
@@ -0,0 +1,264 @@
<template>
<el-dialog
v-model="visible"
:title="editId ? $t('common.edit') : $t('common.add')"
width="600px"
@close="handleClose"
>
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-width="120px"
>
<<range .FormFields>>
<el-form-item :label="$t('<<$.ModuleName>>.<<.Name>>')" prop="<<.Name>>">
<<if eq .FormType "input">>
<el-input v-model="form.<<.Name>>" :placeholder="$t('<<$.ModuleName>>.<<.Name>>')" />
<<else if eq .FormType "textarea">>
<el-input
v-model="form.<<.Name>>"
type="textarea"
:rows="4"
:placeholder="$t('<<$.ModuleName>>.<<.Name>>')" />
<<else if eq .FormType "select">>
<el-select v-model="form.<<.Name>>" :placeholder="$t('common.select')">
<el-option
v-for="item in <<.Name>>Options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<<else if eq .FormType "switch">>
<el-switch v-model="form.<<.Name>>" />
<<else if eq .FormType "date-picker">>
<el-date-picker
v-model="form.<<.Name>>"
type="date"
:placeholder="$t('common.select_date')" style="width: 100%" />
<<else if eq .FormType "datetime-picker">>
<el-date-picker
v-model="form.<<.Name>>"
type="datetime"
:placeholder="$t('common.select_datetime')" style="width: 100%" />
<<else if eq .FormType "image-upload">>
<el-upload
class="image-uploader"
action="/api/admin/attachments/upload"
:show-file-list="false"
:on-success="handleImageSuccess"
>
<img v-if="form.<<.Name>>" :src="form.<<.Name>>" class="image-preview" />
<el-icon v-else class="image-uploader-icon"><Plus /></el-icon>
</el-upload>
<<else if eq .FormType "file-upload">>
<el-upload
action="/api/admin/attachments/upload"
:show-file-list="true"
:on-success="handleFileSuccess"
>
<el-button type="primary">{{ $t('common.upload') }}</el-button>
</el-upload>
<<end>>
</el-form-item>
<<- end>>
</el-form>
<template #footer>
<el-button @click="handleClose">{{ $t('common.cancel') }}</el-button>
<el-button type="primary" :loading="submitting" @click="handleSubmit">
{{ $t('common.confirm') }}
</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import {
<<if .HasCreate>>create<<.ModelName>>,<<end>>
<<if .HasEdit>>update<<.ModelName>>,<<end>>
get<<.ModelName>>Detail
} from '../../api/<<.ModuleName>>'
import { getOptions } from '../../api/option'
import ErrorHandler from '../../utils/errorHandler'
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
editId: {
type: Number,
default: null
}
})
const emit = defineEmits(['update:modelValue', 'success'])
const { t } = useI18n()
const formRef = ref(null)
const submitting = ref(false)
<<range .FormFields>>
<<if eq .FormType "select">>
const <<.Name>>Options = ref([])
<<end>>
<<- end>>
const visible = ref(props.modelValue)
watch(() => props.modelValue, (val) => {
visible.value = val
})
watch(visible, (val) => {
emit('update:modelValue', val)
})
const form = ref({
<<range .FormFields>>
<<.Name>>: null,
<<- end>>
})
const rules = {
<<range .FormFields>>
<<.Name>>: [
{ required: <<.Required>>, message: t('<<$.ModuleName>>.<<.Name>>_required'), trigger: 'blur' }
],
<<- end>>
}
const handleSubmit = async () => {
if (!formRef.value) return
try {
await formRef.value.validate()
submitting.value = true
if (props.editId) {
<<if .HasEdit>>
await update<<.ModelName>>(props.editId, form.value)
ElMessage.success(t('common.update_success'))
<<else>>
ElMessage.error(t('common.operation_failed'))
<<end>>
} else {
<<if .HasCreate>>
await create<<.ModelName>>(form.value)
ElMessage.success(t('common.create_success'))
<<else>>
ElMessage.error(t('common.operation_failed'))
<<end>>
}
emit('success')
handleClose()
} catch (error) {
ErrorHandler.handle(error)
} finally {
submitting.value = false
}
}
const handleClose = () => {
visible.value = false
formRef.value?.resetFields()
}
const handleImageSuccess = (response) => {
form.value.image = response.data.url
}
const handleFileSuccess = (response) => {
form.value.file = response.data.url
}
const loadOptions = async () => {
<<range .FormFields>>
<<if eq .FormType "select">>
try {
<<if eq .Dictionary "">>
//
// const res = await getOptions('<<.Name>>')
// <<.Name>>Options.value = res.data
<<else>>
const res = await getOptions('dictionary', { dictionary_type: '<<.Dictionary>>' })
if (res.data) {
<<.Name>>Options.value = res.data
}
<<end>>
} catch (error) {
console.error('Failed to load <<.Name>> options:', error)
}
<<end>>
<<- end>>
}
const loadData = async () => {
if (!props.editId) return
try {
const res = await get<<.ModelName>>Detail(props.editId)
if (res.data && res.data.<<.ModuleName>>) {
const data = res.data.<<.ModuleName>>
form.value = {
<<range .FormFields>>
<<.Name>>: data.<<.Name>>,
<<- end>>
}
}
} catch (error) {
ErrorHandler.handle(error)
}
}
watch(visible, (val) => {
if (val) {
loadOptions()
if (props.editId) {
loadData()
} else {
formRef.value?.resetFields()
form.value = {
<<range .FormFields>>
<<.Name>>: null,
<<- end>>
}
}
}
})
</script>
<style scoped>
.image-uploader {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
width: 178px;
height: 178px;
display: flex;
align-items: center;
justify-content: center;
}
.image-uploader:hover {
border-color: #409EFF;
}
.image-preview {
width: 178px;
height: 178px;
object-fit: cover;
}
.image-uploader-icon {
font-size: 28px;
color: #8c939d;
}
</style>
+201
View File
@@ -0,0 +1,201 @@
<template>
<div class="<<.ModuleName>>-list">
<el-card>
<template #header>
<div class="card-header">
<span>{{ $t('menu.<<$.ModuleName>>') }}</span>
<<if .HasCreate>>
<el-button type="primary" @click="handleAdd">
<el-icon><Plus /></el-icon>
{{ $t('common.add') }}
</el-button>
<<end>>
</div>
</template>
<SearchForm
:model="searchForm"
:fields="searchFields"
:initial-values="initialSearchForm"
i18n-prefix="<<.ModuleName>>"
@search="handleSearch"
@reset="handleReset"
/>
<VxeTable
ref="tableRef"
:data="tableData"
:loading="loading"
:columns="tableColumns"
:height="600"
@sort-change="handleSortChange"
>
<template #operation="{ row }">
<<if .HasEdit>>
<el-button type="primary" size="small" @click="handleEdit(row)">
{{ $t('common.edit') }}
</el-button>
<<end>>
<<if .HasDelete>>
<el-button type="danger" size="small" @click="handleDelete(row)">
{{ $t('common.delete') }}
</el-button>
<<end>>
</template>
</VxeTable>
<Pagination
v-model="pagination"
:auto-load="true"
:on-page-change="loadData"
/>
<<.ModelName>>Form
ref="formRef"
v-model="dialogVisible"
:edit-id="editId"
@success="handleFormSuccess"
/>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import SearchForm from '../../components/SearchForm.vue'
import Pagination from '../../components/Pagination.vue'
import VxeTable from '../../components/VxeTable.vue'
import <<.ModelName>>Form from './<<.ModelName>>Form.vue'
import { useListPage } from '../../composables/useListPage'
import { useCrud } from '../../composables/useCrud'
import {
get<<.ModelName>>List,
delete<<.ModelName>>
} from '../../api/<<.ModuleName>>'
import logger from '../../utils/logger'
import ErrorHandler from '../../utils/errorHandler'
const { t } = useI18n()
const tableRef = ref(null)
const formRef = ref(null)
const {
dialogVisible,
editId,
handleAdd,
handleClose,
handleDelete: handleDeleteCrud
} = useCrud({
deleteApi: delete<<.ModelName>>
})
const initialSearchForm = {
<<range .SearchableFields>>
<<.Name>>: '',
<<- end>>
}
const {
pagination,
tableData,
loading,
searchForm,
loadData,
handleSearch,
handleReset,
handleSortChange
} = useListPage({
fetchApi: get<<.ModelName>>List,
initialSearchForm,
fieldMapping: {},
defaultSort: 'id:desc',
tableRef: computed(() => tableRef.value?.tableRef)
})
const searchFields = computed(() => [
<<range .SearchableFields>>
{
prop: '<<.Name>>',
label: t('<<$.ModuleName>>.<<.Name>>'),
type: '<<.SearchUIType>>',
<<if .ApiUrl>> apiUrl: '<<.ApiUrl>>',<<end>>
<<if eq .SearchUIType "select">>
<<if eq .Dictionary "">>
// role, department等apiUrl已由.ApiUrl提供
<<else>>
apiUrl: '/options?type=dictionary&dictionary_type=<<.Dictionary>>',
<<end>>
<<end>>
width: '200px',
advanced: false
},
<<- end>>
])
const tableColumns = computed(() => [
{
field: 'id',
title: t('table.id'),
width: 80,
sortable: true
},
<<range .ListFields>>
{
field: '<<.Name>>',
<<if .Relation>>
title: t('<<$.Relation.Table>>.<<$.Relation.DisplayField>>'),
<<else>>
title: t('<<$.ModuleName>>.<<.Name>>'),
<<end>>
sortable: <<.Sortable>>
},
<<if .Relation>>
{
field: '<<.Relation.Table>>_<<.Relation.DisplayField>>',
title: t('<<$.Relation.Table>>.<<$.Relation.DisplayField>>'),
sortable: false
},
<<end>>
<<- end>>
{
field: 'created_at',
title: t('table.created_at'),
width: 180,
sortable: true
},
{
field: 'operation',
title: t('table.operation'),
width: 180,
fixed: 'right',
slot: 'operation'
}
])
const handleEdit = (row) => {
editId.value = row.id
dialogVisible.value = true
}
const handleDelete = async (row) => {
await handleDeleteCrud(row, loadData)
}
const handleFormSuccess = () => {
handleClose()
loadData()
}
onMounted(() => {
loadData()
})
</script>
<style scoped>
.<<.ModuleName>>-list {
padding: 20px;
}
</style>
+27
View File
@@ -0,0 +1,27 @@
package migrations
import (
"github.com/goravel/framework/contracts/database/schema"
"github.com/goravel/framework/facades"
)
type M<<.Timestamp>>Create<<.ModelName>>Table struct {
}
func (m *M<<.Timestamp>>Create<<.ModelName>>Table) Signature() string {
return "<<.Timestamp>>_create_<<.TableName>>_table"
}
func (m *M<<.Timestamp>>Create<<.ModelName>>Table) Up() error {
return facades.Schema().Create("<<.TableName>>", func(table schema.Blueprint) {
table.ID()
<<range .Fields>>
table.<<.MigrationMethod>>("<<.Name>>")<<if .Comment>>.Comment("<<.Comment>>")<<end>>
<<- end>>
table.Timestamps()
table.SoftDeletes()
})
}
func (m *M<<.Timestamp>>Create<<.ModelName>>Table) Down() error {
return facades.Schema().DropIfExists("<<.TableName>>")
}
+36
View File
@@ -0,0 +1,36 @@
package models
import (
"github.com/goravel/framework/database/orm"
)
type <<.ModelName>> struct {
orm.Model
orm.SoftDeletes
<<range .Fields>>
<<.FieldName>> <<.GoType>> `gorm:"<<.Name>>" json:"<<.JsonName>>"<<if .Comment>> comment:"<<.Comment>>"<<end>><<if .Relation>> json:"<<.Relation.Table>>_<<.Relation.DisplayField>>" gorm:"<<.Relation.Table>>;foreignKey:<<.Relation.ForeignKey>>"<<end>>`
<<- end>>
}
func (<<.ModelName>>) TableName() string {
return "<<.TableName>>"
}
func (r *<<.ModelName>>) Serialize() map[string]any {
return map[string]any{
"id": r.ID,
"created_at": r.CreatedAt,
"updated_at": r.UpdatedAt,
<<range .Fields>>
"<<.JsonName>>": r.<<.FieldName>>,
<<end>>
}
}
func (r *<<.ModelName>>) Deserialize(data map[string]any) {
<<range .Fields>>
if val, ok := data["<<.JsonName>>"]; ok {
r.<<.FieldName>> = val.(<<.GoType>>)
}
<<end>>
}
+42
View File
@@ -0,0 +1,42 @@
package admin
import (
"goravel/app/http/trans"
"github.com/goravel/framework/contracts/http"
)
type <<.RequestCreateName>> struct {
<<range .FormFields>>
<<.FieldName>> <<.GoType>> `form:"<<.JsonName>>" json:"<<.JsonName>>"`
<<- end>>
}
func (r *<<.RequestCreateName>>) Authorize(ctx http.Context) error {
return nil
}
func (r *<<.RequestCreateName>>) Rules(ctx http.Context) map[string]string {
rules := map[string]string{
<<range .FormFields>>
"<<.JsonName>>": "<<if .Required>>required<<end>><<if and .Required .Validators>>|<<end>><<range $i, $v := .Validators>><<if $i>>|<<end>><<$v>><<end>>",
<<- end>>
}
return rules
}
func (r *<<.RequestCreateName>>) Messages(ctx http.Context) map[string]string {
return map[string]string{
<<range .FormFields>>
"<<.JsonName>>.required": trans.Get(ctx, "validation_<<.Name>>_required"),
<<- end>>
}
}
func (r *<<.RequestCreateName>>) Attributes(ctx http.Context) map[string]string {
return map[string]string{
<<range .FormFields>>
"<<.JsonName>>": trans.Get(ctx, "validation_<<.Name>>"),
<<- end>>
}
}
+42
View File
@@ -0,0 +1,42 @@
package admin
import (
"goravel/app/http/trans"
"github.com/goravel/framework/contracts/http"
)
type <<.RequestUpdateName>> struct {
<<range .FormFields>>
<<.FieldName>> *<<.GoType>> `form:"<<.JsonName>>" json:"<<.JsonName>>"`
<<- end>>
}
func (r *<<.RequestUpdateName>>) Authorize(ctx http.Context) error {
return nil
}
func (r *<<.RequestUpdateName>>) Rules(ctx http.Context) map[string]string {
rules := map[string]string{
<<range .FormFields>>
"<<.JsonName>>": "<<if .Required>>required<<end>><<if and .Required .Validators>>|<<end>><<range $i, $v := .Validators>><<if $i>>|<<end>><<$v>><<end>>",
<<- end>>
}
return rules
}
func (r *<<.RequestUpdateName>>) Messages(ctx http.Context) map[string]string {
return map[string]string{
<<range .FormFields>>
"<<.JsonName>>.required": trans.Get(ctx, "validation_<<.Name>>_required"),
<<- end>>
}
}
func (r *<<.RequestUpdateName>>) Attributes(ctx http.Context) map[string]string {
return map[string]string{
<<range .FormFields>>
"<<.JsonName>>": trans.Get(ctx, "validation_<<.Name>>"),
<<- end>>
}
}
+131
View File
@@ -0,0 +1,131 @@
package services
import (
"github.com/goravel/framework/contracts/database/orm"
"github.com/goravel/framework/facades"
apperrors "goravel/app/errors"
"goravel/app/http/requests/admin"
"goravel/app/models"
)
type <<.ServiceName>> interface {
GetByID(id uint) (*models.<<.ModelName>>, error)
GetList(filters <<.ModelName>>Filters, page, pageSize int) ([]models.<<.ModelName>>, int64, error)
<<if .HasCreate>>
Create(req *admin.<<.RequestCreateName>>) (*models.<<.ModelName>>, error)
<<end>>
<<if .HasEdit>>
Update(id uint, req *admin.<<.RequestUpdateName>>) (*models.<<.ModelName>>, error)
<<end>>
<<if .HasDelete>>
Delete(id uint) error
<<end>>
}
type <<.ModelName>>Filters struct {
<<range .SearchableFields>>
<<.PascalName>> string
<<- end>>
}
type <<.ServiceName>>Impl struct{}
func New<<.ServiceName>>() <<.ServiceName>> {
return &<<.ServiceName>>Impl{}
}
func Build<<.ModelName>>Query(filters <<.ModelName>>Filters) orm.Query {
query := facades.Orm().Query().Model(&models.<<.ModelName>>{})
<<range .SearchableFields>>
if filters.<<.PascalName>> != "" {
<<if eq .SearchType "like">>
query = query.Where("<<.Name>> LIKE ?", "%"+filters.<<.PascalName>>+"%")
<<else if eq .SearchType "=">>
query = query.Where("<<.Name>> = ?", filters.<<.PascalName>>)
<<else if eq .SearchType ">" >>
query = query.Where("<<.Name>> > ?", filters.<<.PascalName>>)
<<else if eq .SearchType ">=" >>
query = query.Where("<<.Name>> >= ?", filters.<<.PascalName>>)
<<else if eq .SearchType "<" >>
query = query.Where("<<.Name>> < ?", filters.<<.PascalName>>)
<<else if eq .SearchType "<=" >>
query = query.Where("<<.Name>> <= ?", filters.<<.PascalName>>)
<<else if eq .SearchType "!=" >>
query = query.Where("<<.Name>> != ?", filters.<<.PascalName>>)
<<else if eq .SearchType "in">>
query = query.Where("<<.Name>> IN ?", filters.<<.PascalName>>)
<<else>>
query = query.Where("<<.Name>> LIKE ?", "%"+filters.<<.PascalName>>+"%")
<<end>>
}
<<- end>>
return query
}
func (s *<<.ServiceName>>Impl) GetByID(id uint) (*models.<<.ModelName>>, error) {
var item models.<<.ModelName>>
if err := facades.Orm().Query().Where("id", id).FirstOrFail(&item); err != nil {
return nil, apperrors.NewBusinessError("<<.ModuleName>>_not_found", "<<.ModelName>> not found").WithError(err)
}
return &item, nil
}
func (s *<<.ServiceName>>Impl) GetList(filters <<.ModelName>>Filters, page, pageSize int) ([]models.<<.ModelName>>, int64, error) {
query := Build<<.ModelName>>Query(filters)
var list []models.<<.ModelName>>
var total int64
if err := query.Order("id desc").Paginate(page, pageSize, &list, &total); err != nil {
return nil, 0, err
}
return list, total, nil
}
<<if .HasCreate>>
func (s *<<.ServiceName>>Impl) Create(req *admin.<<.RequestCreateName>>) (*models.<<.ModelName>>, error) {
item := &models.<<.ModelName>>{
<<range .FormFields>>
<<.FieldName>>: req.<<.FieldName>>,
<<- end>>
}
if err := facades.Orm().Query().Create(item); err != nil {
return nil, apperrors.ErrCreateFailed.WithError(err)
}
return item, nil
}
<<end>>
<<if .HasEdit>>
func (s *<<.ServiceName>>Impl) Update(id uint, req *admin.<<.RequestUpdateName>>) (*models.<<.ModelName>>, error) {
item, err := s.GetByID(id)
if err != nil {
return nil, err
}
<<range .FormFields>>
if req.<<.FieldName>> != nil {
item.<<.FieldName>> = *req.<<.FieldName>>
}
<<- end>>
if err := facades.Orm().Query().Save(item); err != nil {
return nil, apperrors.ErrUpdateFailed.WithError(err)
}
return item, nil
}
<<end>>
<<if .HasDelete>>
func (s *<<.ServiceName>>Impl) Delete(id uint) error {
if _, err := facades.Orm().Query().Where("id", id).Delete(&models.<<.ModelName>>{}); err != nil {
return err
}
return nil
}
<<end>>