AI代码生成工具
This commit is contained in:
35
app/template/uniapp/PAGES_JSON_SNIPPET.md
Normal file
35
app/template/uniapp/PAGES_JSON_SNIPPET.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# 模板名称 — uniapp 粘贴说明(C 端三页)
|
||||
|
||||
## 落点
|
||||
|
||||
`nl-admin-uniapp/src/pages-sub/my-gen/dashCase/`
|
||||
|
||||
## pages.json 片段
|
||||
|
||||
在 `subPackages` → `root: pages-sub/my-gen` 的 `pages` 追加:
|
||||
|
||||
```json
|
||||
{ "path": "dashCase/pages/list", "style": { "navigationBarTitleText": "模板名称" } },
|
||||
{ "path": "dashCase/pages/detail", "style": { "navigationBarTitleText": "模板名称详情" } },
|
||||
{ "path": "dashCase/pages/form", "style": { "navigationBarTitleText": "编辑模板名称" } }
|
||||
```
|
||||
|
||||
## features.ts 片段
|
||||
|
||||
```ts
|
||||
{
|
||||
key: 'dashCase',
|
||||
title: '模板名称',
|
||||
desc: '代码生成模块',
|
||||
icon: '码',
|
||||
category: 'gen',
|
||||
path: '/pages-sub/my-gen/dashCase/pages/list',
|
||||
keywords: ['模板名称'],
|
||||
}
|
||||
```
|
||||
|
||||
## 强制约定
|
||||
|
||||
- 兼容微信小程序 + App + H5
|
||||
- 交互:列表 → 详情 → 全屏表单;**禁止**底部抽屉做主 CRUD
|
||||
- 复用 `AppCardList` / `AppDetailHero` / `AppInfoGroup` / `AppBottomBar` / `AppPageForm`
|
||||
33
app/template/uniapp/api/index.ts
Normal file
33
app/template/uniapp/api/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 模板名称 API(uniapp)
|
||||
* 粘贴后路径:pages-sub/my-gen/dashCase/api/index.ts
|
||||
* 必须兼容微信小程序 + App + H5
|
||||
*/
|
||||
import { get, post } from '@/utils/request'
|
||||
|
||||
const prefix = 'dashCase/'
|
||||
|
||||
/** 分页列表 */
|
||||
export function getupperCamelCaseList(params: Record<string, any> = {}) {
|
||||
return get<any>(`${prefix}list`, params)
|
||||
}
|
||||
|
||||
/** 详情 */
|
||||
export function getupperCamelCaseInfo(id: number) {
|
||||
return get<any>(`${prefix}detail`, { id })
|
||||
}
|
||||
|
||||
/** 新增 */
|
||||
export function createupperCamelCase(data: Record<string, any>) {
|
||||
return post<any>(`${prefix}create`, data)
|
||||
}
|
||||
|
||||
/** 更新 */
|
||||
export function updateupperCamelCase(data: Record<string, any>) {
|
||||
return post<any>(`${prefix}update`, data)
|
||||
}
|
||||
|
||||
/** 删除 */
|
||||
export function deleteupperCamelCase(data: Record<string, any>) {
|
||||
return post<any>(`${prefix}delete`, data)
|
||||
}
|
||||
58
app/template/uniapp/pages/detail.vue
Normal file
58
app/template/uniapp/pages/detail.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 模板名称详情:信息展示 + 底栏编辑/删除(禁止抽屉主路径)
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app'
|
||||
|
||||
import { deleteupperCamelCase, getupperCamelCaseInfo } from '../api'
|
||||
import AppBottomBar from '@/components/AppBottomBar.vue'
|
||||
import AppDetailHero from '@/components/AppDetailHero.vue'
|
||||
import AppInfoGroup, { type AppInfoRow } from '@/components/AppInfoGroup.vue'
|
||||
|
||||
const id = ref(0)
|
||||
const info = ref<Record<string, any>>({})
|
||||
|
||||
onLoad((q) => { id.value = Number(q?.id || 0) })
|
||||
onShow(async () => {
|
||||
if (id.value) info.value = (await getupperCamelCaseInfo(id.value)) || {}
|
||||
})
|
||||
|
||||
const title = computed(() => String(info.value.UNI_TITLE_FIELD || `模板名称#${id.value}`))
|
||||
const rows = computed<AppInfoRow[]>(() => [
|
||||
// UNI_DETAIL_ROWS
|
||||
{ label: '状态', value: Number(info.value.status) === 0 ? '正常' : '禁用' },
|
||||
{ label: '创建时间', value: info.value.created_at },
|
||||
])
|
||||
|
||||
function goEdit() {
|
||||
uni.navigateTo({ url: `/pages-sub/my-gen/dashCase/pages/form?id=${id.value}` })
|
||||
}
|
||||
|
||||
function onDelete() {
|
||||
uni.showModal({
|
||||
title: '删除确认',
|
||||
content: '确定删除该记录吗?',
|
||||
confirmColor: '#ef4444',
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
await deleteupperCamelCase({ ids: [id.value] })
|
||||
uni.showToast({ title: '已删除', icon: 'success' })
|
||||
setTimeout(() => uni.navigateBack(), 400)
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="nl-page">
|
||||
<AppDetailHero
|
||||
:title="title"
|
||||
:subtitle="String(info.UNI_SUBTITLE_FIELD || '')"
|
||||
:status-text="Number(info.status) === 0 ? '正常' : '禁用'"
|
||||
:status-type="Number(info.status) === 0 ? 'success' : 'danger'"
|
||||
/>
|
||||
<AppInfoGroup title="详细信息" :items="rows" />
|
||||
<AppBottomBar primary-text="编辑" danger-text="删除" @primary="goEdit" @danger="onDelete" />
|
||||
</view>
|
||||
</template>
|
||||
57
app/template/uniapp/pages/form.vue
Normal file
57
app/template/uniapp/pages/form.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 模板名称新建/编辑全屏表单(替代底部抽屉)
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
|
||||
import { createupperCamelCase, getupperCamelCaseInfo, updateupperCamelCase } from '../api'
|
||||
import AppPageForm from '@/components/AppPageForm.vue'
|
||||
|
||||
const id = ref(0)
|
||||
const submitting = ref(false)
|
||||
const form = ref<Record<string, any>>({
|
||||
// UNI_FORM_DEFAULTS
|
||||
})
|
||||
|
||||
const isEdit = computed(() => !!id.value)
|
||||
|
||||
onLoad(async (q) => {
|
||||
id.value = Number(q?.id || 0)
|
||||
if (id.value) {
|
||||
const info = await getupperCamelCaseInfo(id.value)
|
||||
form.value = {
|
||||
// UNI_FORM_ASSIGN
|
||||
}
|
||||
// 回填兜底
|
||||
Object.assign(form.value, info || {})
|
||||
}
|
||||
})
|
||||
|
||||
async function onSubmit() {
|
||||
submitting.value = true
|
||||
try {
|
||||
if (isEdit.value) await updateupperCamelCase({ id: id.value, ...form.value })
|
||||
else await createupperCamelCase({ ...form.value })
|
||||
uni.showToast({ title: '保存成功', icon: 'success' })
|
||||
setTimeout(() => uni.navigateBack(), 400)
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppPageForm tip="请填写模板名称信息后保存。" :loading="submitting" @submit="onSubmit">
|
||||
<!-- UNI_FORM_FIELDS -->
|
||||
</AppPageForm>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-item {
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
min-height: 100rpx; border-bottom: 1rpx solid $nl-color-border;
|
||||
}
|
||||
.label { width: 160rpx; color: $nl-color-text-secondary; font-size: 28rpx; }
|
||||
.input { flex: 1; text-align: right; font-size: 28rpx; }
|
||||
</style>
|
||||
120
app/template/uniapp/pages/list.vue
Normal file
120
app/template/uniapp/pages/list.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 模板名称列表(C 端):点击进详情,新增进全屏表单
|
||||
* 兼容微信小程序 / App / H5
|
||||
*/
|
||||
import { computed, ref } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
|
||||
import { getupperCamelCaseList } from '../api'
|
||||
import AppCardList, { type AppCardItem } from '@/components/AppCardList.vue'
|
||||
import AppEmpty from '@/components/AppEmpty.vue'
|
||||
import AppFilterBar from '@/components/AppFilterBar.vue'
|
||||
import AppSearchBar from '@/components/AppSearchBar.vue'
|
||||
import { usePullRefresh } from '@/composables/usePullRefresh'
|
||||
|
||||
const list = ref<any[]>([])
|
||||
const keyword = ref('')
|
||||
const draftKeyword = ref('')
|
||||
const loading = ref(false)
|
||||
const page = ref(1)
|
||||
const finished = ref(false)
|
||||
|
||||
const selectedCount = computed(() => (keyword.value ? 1 : 0))
|
||||
|
||||
const cards = computed<AppCardItem[]>(() =>
|
||||
list.value.map((item) => ({
|
||||
id: item.id,
|
||||
title: String(item.UNI_TITLE_FIELD || `模板名称#${item.id}`),
|
||||
subtitle: String(item.UNI_SUBTITLE_FIELD || ''),
|
||||
iconText: String(item.UNI_TITLE_FIELD || '模').slice(0, 1),
|
||||
statusText: Number(item.status) === 0 ? '正常' : '禁用',
|
||||
statusType: Number(item.status) === 0 ? 'success' : 'danger',
|
||||
})),
|
||||
)
|
||||
|
||||
onShow(() => reload())
|
||||
// pages.json 该页需 enablePullDownRefresh: true
|
||||
usePullRefresh(reload)
|
||||
|
||||
async function reload() {
|
||||
page.value = 1
|
||||
finished.value = false
|
||||
list.value = []
|
||||
await loadMore()
|
||||
}
|
||||
|
||||
async function loadMore() {
|
||||
if (loading.value || finished.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getupperCamelCaseList({
|
||||
page: page.value,
|
||||
pageSize: 20,
|
||||
keyword: keyword.value || undefined,
|
||||
})
|
||||
const items = res?.items || res?.data || []
|
||||
list.value = page.value === 1 ? items : list.value.concat(items)
|
||||
const total = Number(res?.total || 0)
|
||||
if (!items.length || list.value.length >= total) finished.value = true
|
||||
else page.value += 1
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onFilterReset() {
|
||||
draftKeyword.value = ''
|
||||
}
|
||||
|
||||
function onFilterConfirm() {
|
||||
keyword.value = draftKeyword.value
|
||||
reload()
|
||||
}
|
||||
|
||||
function goDetail(item: AppCardItem) {
|
||||
uni.navigateTo({ url: `/pages-sub/my-gen/dashCase/pages/detail?id=${item.id}` })
|
||||
}
|
||||
|
||||
function goCreate() {
|
||||
uni.navigateTo({ url: '/pages-sub/my-gen/dashCase/pages/form' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="nl-page page">
|
||||
<AppSearchBar
|
||||
v-model="keyword"
|
||||
placeholder="搜索模板名称"
|
||||
@search="(v) => { keyword = v; reload() }"
|
||||
@clear="() => { keyword = ''; reload() }"
|
||||
/>
|
||||
<AppFilterBar :selected-count="selectedCount" @reset="onFilterReset" @confirm="onFilterConfirm">
|
||||
<view class="filter-row">
|
||||
<text>关键词</text>
|
||||
<input v-model="draftKeyword" class="filter-input" placeholder="关键词" />
|
||||
</view>
|
||||
</AppFilterBar>
|
||||
<AppCardList v-if="cards.length" :list="cards" @select="goDetail" />
|
||||
<AppEmpty v-else text="暂无数据" />
|
||||
<view v-if="cards.length" class="more" @tap="loadMore">
|
||||
{{ finished ? '没有更多了' : loading ? '加载中…' : '加载更多' }}
|
||||
</view>
|
||||
<view class="fab" @tap="goCreate">新增</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page { padding-bottom: 160rpx; }
|
||||
.filter-row {
|
||||
display: flex; align-items: center; justify-content: space-between; min-height: 72rpx; font-size: 26rpx;
|
||||
}
|
||||
.filter-input { flex: 1; text-align: right; margin-left: 24rpx; }
|
||||
.more { text-align: center; color: $nl-color-text-muted; padding: 16rpx; font-size: 24rpx; }
|
||||
.fab {
|
||||
position: fixed; right: 32rpx; bottom: calc(48rpx + env(safe-area-inset-bottom));
|
||||
min-width: 120rpx; height: 88rpx; padding: 0 36rpx; border-radius: 999rpx;
|
||||
background: $nl-color-primary; color: #fff; display: flex; align-items: center; justify-content: center;
|
||||
font-weight: 700; box-shadow: 0 16rpx 40rpx rgba(255, 107, 0, 0.35);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user