后台编写王朝
Some checks failed
Deploy Pages / build (push) Has been cancelled
Deploy Pages / deploy (push) Has been cancelled

This commit is contained in:
aiShuiJiaoDeXioShou 2024-10-12 11:13:19 +08:00
parent 4f1b8cbe9d
commit 2bbb32adf6
61 changed files with 20904 additions and 158 deletions

View File

@ -22,7 +22,7 @@
"editor.defaultFormatter": "foxundermoon.shell-format"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "Vue.volar"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"

4
env/.env vendored
View File

@ -7,9 +7,11 @@ VITE_WX_APPID = 'wxa2abb91f64032a2b'
# h5部署网站的base配置到 manifest.config.ts 里的 h5.router.base
VITE_APP_PUBLIC_BASE=/yskj/
VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
VITE_SERVER_BASEURL = 'http://localhost:8080/api'
VITE_UPLOAD_BASEURL = 'https://ukw0y1.laf.run/upload'
VITE_STATIC_BASEURL = 'http://localhost:8080/'
# h5是否需要配置代理
VITE_APP_PROXY=false
VITE_APP_PROXY_PREFIX = '/api'

View File

@ -35,8 +35,8 @@ export default defineUniPages({
{
iconPath: 'static/tabbar/example.png',
selectedIconPath: 'static/tabbar/exampleHL.png',
pagePath: 'pages/about/about',
text: '关于',
pagePath: 'pages/shop/index',
text: '商城',
},
],
},

7
server/mall/.env.example Normal file
View File

@ -0,0 +1,7 @@
HOST=0.0.0.0
PORT=8080
APP_KEYS="toBeModified1,toBeModified2"
API_TOKEN_SALT=tobemodified
ADMIN_JWT_SECRET=tobemodified
TRANSFER_TOKEN_SALT=tobemodified
JWT_SECRET=tobemodified

131
server/mall/.gitignore vendored Normal file
View File

@ -0,0 +1,131 @@
############################
# OS X
############################
.DS_Store
.AppleDouble
.LSOverride
Icon
.Spotlight-V100
.Trashes
._*
############################
# Linux
############################
*~
############################
# Windows
############################
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
*.cab
*.msi
*.msm
*.msp
############################
# Packages
############################
*.7z
*.csv
*.dat
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
*.com
*.class
*.dll
*.exe
*.o
*.seed
*.so
*.swo
*.swp
*.swn
*.swm
*.out
*.pid
############################
# Logs and databases
############################
.tmp
*.log
*.sql
*.sqlite
*.sqlite3
############################
# Misc.
############################
*#
ssl
.idea
nbproject
public/uploads/*
!public/uploads/.gitkeep
.tsbuildinfo
.eslintcache
############################
# Node.js
############################
lib-cov
lcov.info
pids
logs
results
node_modules
.node_history
############################
# Package managers
############################
.yarn/*
!.yarn/cache
!.yarn/unplugged
!.yarn/patches
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
yarn-error.log
############################
# Tests
############################
coverage
############################
# Strapi
############################
.env
license.txt
exports
.strapi
dist
build
.strapi-updater.json
.strapi-cloud.json

61
server/mall/README.md Normal file
View File

@ -0,0 +1,61 @@
# 🚀 Getting started with Strapi
Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/dev-docs/cli) (CLI) which lets you scaffold and manage your project in seconds.
### `develop`
Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-develop)
```
npm run develop
# or
yarn develop
```
### `start`
Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-start)
```
npm run start
# or
yarn start
```
### `build`
Build your admin panel. [Learn more](https://docs.strapi.io/dev-docs/cli#strapi-build)
```
npm run build
# or
yarn build
```
## ⚙️ Deployment
Strapi gives you many possible deployment options for your project including [Strapi Cloud](https://cloud.strapi.io). Browse the [deployment section of the documentation](https://docs.strapi.io/dev-docs/deployment) to find the best solution for your use case.
```
yarn strapi deploy
```
## 📚 Learn more
- [Resource center](https://strapi.io/resource-center) - Strapi resource center.
- [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation.
- [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community.
- [Strapi blog](https://strapi.io/blog) - Official Strapi blog containing articles made by the Strapi team and the community.
- [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements.
Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome!
## ✨ Community
- [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team.
- [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members.
- [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi.
---
<sub>🤫 Psst! [Strapi is hiring](https://strapi.io/careers).</sub>

View File

@ -0,0 +1,17 @@
export default ({ env }) => ({
auth: {
secret: env('ADMIN_JWT_SECRET'),
},
apiToken: {
salt: env('API_TOKEN_SALT'),
},
transfer: {
token: {
salt: env('TRANSFER_TOKEN_SALT'),
},
},
flags: {
nps: env.bool('FLAG_NPS', true),
promoteEE: env.bool('FLAG_PROMOTE_EE', true),
},
});

View File

@ -0,0 +1,7 @@
export default {
rest: {
defaultLimit: 25,
maxLimit: 100,
withCount: true,
},
};

View File

@ -0,0 +1,60 @@
import path from 'path';
export default ({ env }) => {
const client = env('DATABASE_CLIENT', 'sqlite');
const connections = {
mysql: {
connection: {
host: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 3306),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
ssl: env.bool('DATABASE_SSL', false) && {
key: env('DATABASE_SSL_KEY', undefined),
cert: env('DATABASE_SSL_CERT', undefined),
ca: env('DATABASE_SSL_CA', undefined),
capath: env('DATABASE_SSL_CAPATH', undefined),
cipher: env('DATABASE_SSL_CIPHER', undefined),
rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', true),
},
},
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
},
postgres: {
connection: {
connectionString: env('DATABASE_URL'),
host: env('DATABASE_HOST', 'localhost'),
port: env.int('DATABASE_PORT', 5432),
database: env('DATABASE_NAME', 'strapi'),
user: env('DATABASE_USERNAME', 'strapi'),
password: env('DATABASE_PASSWORD', 'strapi'),
ssl: env.bool('DATABASE_SSL', false) && {
key: env('DATABASE_SSL_KEY', undefined),
cert: env('DATABASE_SSL_CERT', undefined),
ca: env('DATABASE_SSL_CA', undefined),
capath: env('DATABASE_SSL_CAPATH', undefined),
cipher: env('DATABASE_SSL_CIPHER', undefined),
rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', true),
},
schema: env('DATABASE_SCHEMA', 'public'),
},
pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) },
},
sqlite: {
connection: {
filename: path.join(__dirname, '..', '..', env('DATABASE_FILENAME', '.tmp/data.db')),
},
useNullAsDefault: true,
},
};
return {
connection: {
client,
...connections[client],
acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000),
},
};
};

View File

@ -0,0 +1,12 @@
export default [
'strapi::logger',
'strapi::errors',
'strapi::security',
'strapi::cors',
'strapi::poweredBy',
'strapi::query',
'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
];

View File

@ -0,0 +1 @@
export default () => ({});

View File

@ -0,0 +1,7 @@
export default ({ env }) => ({
host: env('HOST', '0.0.0.0'),
port: env.int('PORT', 1337),
app: {
keys: env.array('APP_KEYS'),
},
});

View File

BIN
server/mall/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

18734
server/mall/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

37
server/mall/package.json Normal file
View File

@ -0,0 +1,37 @@
{
"name": "mall",
"version": "0.1.0",
"private": true,
"description": "A Strapi application",
"scripts": {
"build": "strapi build",
"deploy": "strapi deploy",
"develop": "strapi develop",
"start": "strapi start",
"strapi": "strapi"
},
"dependencies": {
"@strapi/plugin-cloud": "5.0.5",
"@strapi/plugin-color-picker": "^5.0.5",
"@strapi/plugin-users-permissions": "5.0.5",
"@strapi/strapi": "5.0.5",
"better-sqlite3": "11.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-router-dom": "^6.0.0",
"styled-components": "^6.0.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5"
},
"engines": {
"node": ">=18.0.0 <=22.x.x",
"npm": ">=6.0.0"
},
"strapi": {
"uuid": "ff207221-3a78-479c-83e0-36bb841142ce"
}
}

View File

@ -0,0 +1,3 @@
# To prevent search engines from seeing the site altogether, uncomment the next two lines:
# User-Agent: *
# Disallow: /

View File

View File

@ -0,0 +1,37 @@
import type { StrapiApp } from '@strapi/strapi/admin';
export default {
config: {
locales: [
// 'ar',
// 'fr',
// 'cs',
// 'de',
// 'dk',
// 'es',
// 'he',
// 'id',
// 'it',
// 'ja',
// 'ko',
// 'ms',
// 'nl',
// 'no',
// 'pl',
// 'pt-BR',
// 'pt',
// 'ru',
// 'sk',
// 'sv',
// 'th',
// 'tr',
// 'uk',
// 'vi',
// 'zh-Hans',
// 'zh',
],
},
bootstrap(app: StrapiApp) {
console.log(app);
},
};

View File

@ -0,0 +1,15 @@
export default {
config: {
locales: ['zh-Hans'],
translations: {
'zh-Hans': {
'Auth.form.email.label': '1471299010@qq.com',
Users: '1471299010@qq.com',
City: 'Chinese (Simplified) (zh-Hans)',
// 这里是刚刚在设置中新建的国际化语言版本的ID
Id: '3',
},
},
},
bootstrap() { },
}

View File

@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Bundler",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["../plugins/**/admin/src/**/*", "./"],
"exclude": ["node_modules/", "build/", "dist/", "**/*.test.ts"]
}

View File

@ -0,0 +1,12 @@
import { mergeConfig, type UserConfig } from 'vite';
export default (config: UserConfig) => {
// Important: always return the modified config
return mergeConfig(config, {
resolve: {
alias: {
'@': '/src',
},
},
});
};

View File

View File

@ -0,0 +1,38 @@
{
"kind": "collectionType",
"collectionName": "categorys",
"info": {
"singularName": "category",
"pluralName": "categorys",
"displayName": "分类",
"description": ""
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"categoryName": {
"type": "string",
"required": true,
"unique": true
},
"icon": {
"type": "media",
"multiple": false,
"required": false,
"allowedTypes": [
"images",
"files",
"videos",
"audios"
]
},
"products": {
"type": "relation",
"relation": "manyToMany",
"target": "api::product.product",
"inversedBy": "categoryType"
}
}
}

View File

@ -0,0 +1,7 @@
/**
* category controller
*/
import { factories } from '@strapi/strapi'
export default factories.createCoreController('api::category.category');

View File

@ -0,0 +1,7 @@
/**
* category router
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreRouter('api::category.category');

View File

@ -0,0 +1,7 @@
/**
* category service
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreService('api::category.category');

View File

@ -0,0 +1,56 @@
{
"kind": "collectionType",
"collectionName": "products",
"info": {
"singularName": "product",
"pluralName": "products",
"displayName": "商品",
"description": ""
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"name": {
"type": "string"
},
"description": {
"type": "richtext"
},
"product_image": {
"type": "media",
"multiple": false,
"required": false,
"allowedTypes": [
"images",
"files",
"videos",
"audios"
]
},
"categoryType": {
"type": "relation",
"relation": "manyToMany",
"target": "api::category.category",
"mappedBy": "products"
},
"product_images": {
"type": "media",
"multiple": true,
"required": false,
"allowedTypes": [
"images",
"files",
"videos",
"audios"
]
},
"tags": {
"type": "relation",
"relation": "manyToMany",
"target": "api::tag.tag",
"inversedBy": "tagType"
}
}
}

View File

@ -0,0 +1,7 @@
/**
* product controller
*/
import { factories } from '@strapi/strapi'
export default factories.createCoreController('api::product.product');

View File

@ -0,0 +1,7 @@
/**
* product router
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreRouter('api::product.product');

View File

@ -0,0 +1,7 @@
/**
* product service
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreService('api::product.product');

View File

@ -0,0 +1,37 @@
{
"kind": "collectionType",
"collectionName": "recommends",
"info": {
"singularName": "recommend",
"pluralName": "recommends",
"displayName": "推广"
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"title": {
"type": "string"
},
"image": {
"allowedTypes": [
"images",
"files",
"videos",
"audios"
],
"type": "media",
"multiple": true
},
"is_on": {
"type": "boolean",
"default": true
},
"products": {
"type": "relation",
"relation": "oneToMany",
"target": "api::product.product"
}
}
}

View File

@ -0,0 +1,7 @@
/**
* recommend controller
*/
import { factories } from '@strapi/strapi'
export default factories.createCoreController('api::recommend.recommend');

View File

@ -0,0 +1,7 @@
/**
* recommend router
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreRouter('api::recommend.recommend');

View File

@ -0,0 +1,7 @@
/**
* recommend service
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreService('api::recommend.recommend');

View File

@ -0,0 +1,32 @@
{
"kind": "collectionType",
"collectionName": "tags",
"info": {
"singularName": "tag",
"pluralName": "tags",
"displayName": "标签"
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"tag": {
"type": "string",
"required": true,
"unique": true
},
"color": {
"type": "customField",
"regex": "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$",
"customField": "plugin::color-picker.color",
"required": true
},
"tagType": {
"type": "relation",
"relation": "manyToMany",
"target": "api::product.product",
"mappedBy": "tags"
}
}
}

View File

@ -0,0 +1,7 @@
/**
* tag controller
*/
import { factories } from '@strapi/strapi'
export default factories.createCoreController('api::tag.tag');

View File

@ -0,0 +1,7 @@
/**
* tag router
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreRouter('api::tag.tag');

View File

@ -0,0 +1,7 @@
/**
* tag service
*/
import { factories } from '@strapi/strapi';
export default factories.createCoreService('api::tag.tag');

View File

@ -0,0 +1,19 @@
{
"collectionName": "components_field_promotion_components",
"info": {
"displayName": "PromotionComponent"
},
"options": {},
"attributes": {
"img": {
"allowedTypes": [
"images",
"files",
"videos",
"audios"
],
"type": "media",
"multiple": false
}
}
}

View File

20
server/mall/src/index.ts Normal file
View File

@ -0,0 +1,20 @@
// import type { Core } from '@strapi/strapi';
export default {
/**
* An asynchronous register function that runs before
* your application is initialized.
*
* This gives you an opportunity to extend code.
*/
register(/* { strapi }: { strapi: Core.Strapi } */) {},
/**
* An asynchronous bootstrap function that runs before
* your application gets started.
*
* This gives you an opportunity to set up your data model,
* run jobs, or perform some special logic.
*/
bootstrap(/* { strapi }: { strapi: Core.Strapi } */) {},
};

43
server/mall/tsconfig.json Normal file
View File

@ -0,0 +1,43 @@
{
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "Node",
"lib": ["ES2020"],
"target": "ES2019",
"strict": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"incremental": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"noEmitOnError": true,
"noImplicitThis": true,
"outDir": "dist",
"rootDir": "."
},
"include": [
// Include root files
"./",
// Include all ts files
"./**/*.ts",
// Include all js files
"./**/*.js",
// Force the JSON files in the src folder to be included
"src/**/*.json"
],
"exclude": [
"node_modules/",
"build/",
"dist/",
".cache/",
".tmp/",
// Do not include admin files in the server compilation
"src/admin/",
// Do not include test files
"**/*.test.*",
// Do not include plugins in the server compilation
"src/plugins/**"
]
}

View File

@ -0,0 +1,19 @@
import type { Struct, Schema } from '@strapi/strapi'
export interface FieldPromotionComponent extends Struct.ComponentSchema {
collectionName: 'components_field_promotion_components'
info: {
displayName: 'PromotionComponent'
}
attributes: {
img: Schema.Attribute.Media<'images' | 'files' | 'videos' | 'audios'>
}
}
declare module '@strapi/strapi' {
export module Public {
export interface ComponentSchemas {
'field.promotion-component': FieldPromotionComponent
}
}
}

View File

@ -0,0 +1,859 @@
import type { Struct, Schema } from '@strapi/strapi'
export interface PluginUploadFile extends Struct.CollectionTypeSchema {
collectionName: 'files'
info: {
singularName: 'file'
pluralName: 'files'
displayName: 'File'
description: ''
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String & Schema.Attribute.Required
alternativeText: Schema.Attribute.String
caption: Schema.Attribute.String
width: Schema.Attribute.Integer
height: Schema.Attribute.Integer
formats: Schema.Attribute.JSON
hash: Schema.Attribute.String & Schema.Attribute.Required
ext: Schema.Attribute.String
mime: Schema.Attribute.String & Schema.Attribute.Required
size: Schema.Attribute.Decimal & Schema.Attribute.Required
url: Schema.Attribute.String & Schema.Attribute.Required
previewUrl: Schema.Attribute.String
provider: Schema.Attribute.String & Schema.Attribute.Required
provider_metadata: Schema.Attribute.JSON
related: Schema.Attribute.Relation<'morphToMany'>
folder: Schema.Attribute.Relation<'manyToOne', 'plugin::upload.folder'> &
Schema.Attribute.Private
folderPath: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.Private &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::upload.file'>
}
}
export interface PluginUploadFolder extends Struct.CollectionTypeSchema {
collectionName: 'upload_folders'
info: {
singularName: 'folder'
pluralName: 'folders'
displayName: 'Folder'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
pathId: Schema.Attribute.Integer & Schema.Attribute.Required & Schema.Attribute.Unique
parent: Schema.Attribute.Relation<'manyToOne', 'plugin::upload.folder'>
children: Schema.Attribute.Relation<'oneToMany', 'plugin::upload.folder'>
files: Schema.Attribute.Relation<'oneToMany', 'plugin::upload.file'>
path: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::upload.folder'>
}
}
export interface PluginI18NLocale extends Struct.CollectionTypeSchema {
collectionName: 'i18n_locale'
info: {
singularName: 'locale'
pluralName: 'locales'
collectionName: 'locales'
displayName: 'Locale'
description: ''
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String &
Schema.Attribute.SetMinMax<
{
min: 1
max: 50
},
number
>
code: Schema.Attribute.String & Schema.Attribute.Unique
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::i18n.locale'>
}
}
export interface PluginContentReleasesRelease extends Struct.CollectionTypeSchema {
collectionName: 'strapi_releases'
info: {
singularName: 'release'
pluralName: 'releases'
displayName: 'Release'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String & Schema.Attribute.Required
releasedAt: Schema.Attribute.DateTime
scheduledAt: Schema.Attribute.DateTime
timezone: Schema.Attribute.String
status: Schema.Attribute.Enumeration<['ready', 'blocked', 'failed', 'done', 'empty']> &
Schema.Attribute.Required
actions: Schema.Attribute.Relation<'oneToMany', 'plugin::content-releases.release-action'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::content-releases.release'>
}
}
export interface PluginContentReleasesReleaseAction extends Struct.CollectionTypeSchema {
collectionName: 'strapi_release_actions'
info: {
singularName: 'release-action'
pluralName: 'release-actions'
displayName: 'Release Action'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
type: Schema.Attribute.Enumeration<['publish', 'unpublish']> & Schema.Attribute.Required
contentType: Schema.Attribute.String & Schema.Attribute.Required
entryDocumentId: Schema.Attribute.String
locale: Schema.Attribute.String
release: Schema.Attribute.Relation<'manyToOne', 'plugin::content-releases.release'>
isEntryValid: Schema.Attribute.Boolean
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::content-releases.release-action'>
}
}
export interface PluginReviewWorkflowsWorkflow extends Struct.CollectionTypeSchema {
collectionName: 'strapi_workflows'
info: {
name: 'Workflow'
description: ''
singularName: 'workflow'
pluralName: 'workflows'
displayName: 'Workflow'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String & Schema.Attribute.Required & Schema.Attribute.Unique
stages: Schema.Attribute.Relation<'oneToMany', 'plugin::review-workflows.workflow-stage'>
contentTypes: Schema.Attribute.JSON &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<'[]'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::review-workflows.workflow'>
}
}
export interface PluginReviewWorkflowsWorkflowStage extends Struct.CollectionTypeSchema {
collectionName: 'strapi_workflows_stages'
info: {
name: 'Workflow Stage'
description: ''
singularName: 'workflow-stage'
pluralName: 'workflow-stages'
displayName: 'Stages'
}
options: {
version: '1.1.0'
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String
color: Schema.Attribute.String & Schema.Attribute.DefaultTo<'#4945FF'>
workflow: Schema.Attribute.Relation<'manyToOne', 'plugin::review-workflows.workflow'>
permissions: Schema.Attribute.Relation<'manyToMany', 'admin::permission'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::review-workflows.workflow-stage'>
}
}
export interface PluginUsersPermissionsPermission extends Struct.CollectionTypeSchema {
collectionName: 'up_permissions'
info: {
name: 'permission'
description: ''
singularName: 'permission'
pluralName: 'permissions'
displayName: 'Permission'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
action: Schema.Attribute.String & Schema.Attribute.Required
role: Schema.Attribute.Relation<'manyToOne', 'plugin::users-permissions.role'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::users-permissions.permission'>
}
}
export interface PluginUsersPermissionsRole extends Struct.CollectionTypeSchema {
collectionName: 'up_roles'
info: {
name: 'role'
description: ''
singularName: 'role'
pluralName: 'roles'
displayName: 'Role'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 3
}>
description: Schema.Attribute.String
type: Schema.Attribute.String & Schema.Attribute.Unique
permissions: Schema.Attribute.Relation<'oneToMany', 'plugin::users-permissions.permission'>
users: Schema.Attribute.Relation<'oneToMany', 'plugin::users-permissions.user'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::users-permissions.role'>
}
}
export interface PluginUsersPermissionsUser extends Struct.CollectionTypeSchema {
collectionName: 'up_users'
info: {
name: 'user'
description: ''
singularName: 'user'
pluralName: 'users'
displayName: 'User'
}
options: {
timestamps: true
draftAndPublish: false
}
attributes: {
username: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.Unique &
Schema.Attribute.SetMinMaxLength<{
minLength: 3
}>
email: Schema.Attribute.Email &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 6
}>
provider: Schema.Attribute.String
password: Schema.Attribute.Password &
Schema.Attribute.Private &
Schema.Attribute.SetMinMaxLength<{
minLength: 6
}>
resetPasswordToken: Schema.Attribute.String & Schema.Attribute.Private
confirmationToken: Schema.Attribute.String & Schema.Attribute.Private
confirmed: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo<false>
blocked: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo<false>
role: Schema.Attribute.Relation<'manyToOne', 'plugin::users-permissions.role'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'plugin::users-permissions.user'>
}
}
export interface ApiCategoryCategory extends Struct.CollectionTypeSchema {
collectionName: 'categorys'
info: {
singularName: 'category'
pluralName: 'categorys'
displayName: '\u5206\u7C7B'
description: ''
}
options: {
draftAndPublish: true
}
attributes: {
categoryName: Schema.Attribute.String & Schema.Attribute.Required & Schema.Attribute.Unique
icon: Schema.Attribute.Media<'images' | 'files' | 'videos' | 'audios'>
products: Schema.Attribute.Relation<'manyToMany', 'api::product.product'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'api::category.category'>
}
}
export interface ApiProductProduct extends Struct.CollectionTypeSchema {
collectionName: 'products'
info: {
singularName: 'product'
pluralName: 'products'
displayName: '\u5546\u54C1'
description: ''
}
options: {
draftAndPublish: true
}
attributes: {
name: Schema.Attribute.String
description: Schema.Attribute.RichText
product_image: Schema.Attribute.Media<'images' | 'files' | 'videos' | 'audios'>
categoryType: Schema.Attribute.Relation<'manyToMany', 'api::category.category'>
product_images: Schema.Attribute.Media<'images' | 'files' | 'videos' | 'audios', true>
tags: Schema.Attribute.Relation<'manyToMany', 'api::tag.tag'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'api::product.product'>
}
}
export interface ApiRecommendRecommend extends Struct.CollectionTypeSchema {
collectionName: 'recommends'
info: {
singularName: 'recommend'
pluralName: 'recommends'
displayName: '\u63A8\u5E7F'
}
options: {
draftAndPublish: true
}
attributes: {
title: Schema.Attribute.String
image: Schema.Attribute.Media<'images' | 'files' | 'videos' | 'audios', true>
is_on: Schema.Attribute.Boolean & Schema.Attribute.DefaultTo<true>
products: Schema.Attribute.Relation<'oneToMany', 'api::product.product'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'api::recommend.recommend'>
}
}
export interface ApiTagTag extends Struct.CollectionTypeSchema {
collectionName: 'tags'
info: {
singularName: 'tag'
pluralName: 'tags'
displayName: '\u6807\u7B7E'
}
options: {
draftAndPublish: true
}
attributes: {
tag: Schema.Attribute.String & Schema.Attribute.Required & Schema.Attribute.Unique
color: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.CustomField<'plugin::color-picker.color'>
tagType: Schema.Attribute.Relation<'manyToMany', 'api::product.product'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'api::tag.tag'>
}
}
export interface AdminPermission extends Struct.CollectionTypeSchema {
collectionName: 'admin_permissions'
info: {
name: 'Permission'
description: ''
singularName: 'permission'
pluralName: 'permissions'
displayName: 'Permission'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
action: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
actionParameters: Schema.Attribute.JSON & Schema.Attribute.DefaultTo<{}>
subject: Schema.Attribute.String &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
properties: Schema.Attribute.JSON & Schema.Attribute.DefaultTo<{}>
conditions: Schema.Attribute.JSON & Schema.Attribute.DefaultTo<[]>
role: Schema.Attribute.Relation<'manyToOne', 'admin::role'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::permission'>
}
}
export interface AdminUser extends Struct.CollectionTypeSchema {
collectionName: 'admin_users'
info: {
name: 'User'
description: ''
singularName: 'user'
pluralName: 'users'
displayName: 'User'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
firstname: Schema.Attribute.String &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
lastname: Schema.Attribute.String &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
username: Schema.Attribute.String
email: Schema.Attribute.Email &
Schema.Attribute.Required &
Schema.Attribute.Private &
Schema.Attribute.Unique &
Schema.Attribute.SetMinMaxLength<{
minLength: 6
}>
password: Schema.Attribute.Password &
Schema.Attribute.Private &
Schema.Attribute.SetMinMaxLength<{
minLength: 6
}>
resetPasswordToken: Schema.Attribute.String & Schema.Attribute.Private
registrationToken: Schema.Attribute.String & Schema.Attribute.Private
isActive: Schema.Attribute.Boolean &
Schema.Attribute.Private &
Schema.Attribute.DefaultTo<false>
roles: Schema.Attribute.Relation<'manyToMany', 'admin::role'> & Schema.Attribute.Private
blocked: Schema.Attribute.Boolean & Schema.Attribute.Private & Schema.Attribute.DefaultTo<false>
preferedLanguage: Schema.Attribute.String
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::user'>
}
}
export interface AdminRole extends Struct.CollectionTypeSchema {
collectionName: 'admin_roles'
info: {
name: 'Role'
description: ''
singularName: 'role'
pluralName: 'roles'
displayName: 'Role'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.Unique &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
code: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.Unique &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
description: Schema.Attribute.String
users: Schema.Attribute.Relation<'manyToMany', 'admin::user'>
permissions: Schema.Attribute.Relation<'oneToMany', 'admin::permission'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::role'>
}
}
export interface AdminApiToken extends Struct.CollectionTypeSchema {
collectionName: 'strapi_api_tokens'
info: {
name: 'Api Token'
singularName: 'api-token'
pluralName: 'api-tokens'
displayName: 'Api Token'
description: ''
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.Unique &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
description: Schema.Attribute.String &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}> &
Schema.Attribute.DefaultTo<''>
type: Schema.Attribute.Enumeration<['read-only', 'full-access', 'custom']> &
Schema.Attribute.Required &
Schema.Attribute.DefaultTo<'read-only'>
accessKey: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
lastUsedAt: Schema.Attribute.DateTime
permissions: Schema.Attribute.Relation<'oneToMany', 'admin::api-token-permission'>
expiresAt: Schema.Attribute.DateTime
lifespan: Schema.Attribute.BigInteger
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::api-token'>
}
}
export interface AdminApiTokenPermission extends Struct.CollectionTypeSchema {
collectionName: 'strapi_api_token_permissions'
info: {
name: 'API Token Permission'
description: ''
singularName: 'api-token-permission'
pluralName: 'api-token-permissions'
displayName: 'API Token Permission'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
action: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
token: Schema.Attribute.Relation<'manyToOne', 'admin::api-token'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::api-token-permission'>
}
}
export interface AdminTransferToken extends Struct.CollectionTypeSchema {
collectionName: 'strapi_transfer_tokens'
info: {
name: 'Transfer Token'
singularName: 'transfer-token'
pluralName: 'transfer-tokens'
displayName: 'Transfer Token'
description: ''
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
name: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.Unique &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
description: Schema.Attribute.String &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}> &
Schema.Attribute.DefaultTo<''>
accessKey: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
lastUsedAt: Schema.Attribute.DateTime
permissions: Schema.Attribute.Relation<'oneToMany', 'admin::transfer-token-permission'>
expiresAt: Schema.Attribute.DateTime
lifespan: Schema.Attribute.BigInteger
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::transfer-token'>
}
}
export interface AdminTransferTokenPermission extends Struct.CollectionTypeSchema {
collectionName: 'strapi_transfer_token_permissions'
info: {
name: 'Transfer Token Permission'
description: ''
singularName: 'transfer-token-permission'
pluralName: 'transfer-token-permissions'
displayName: 'Transfer Token Permission'
}
options: {
draftAndPublish: false
}
pluginOptions: {
'content-manager': {
visible: false
}
'content-type-builder': {
visible: false
}
}
attributes: {
action: Schema.Attribute.String &
Schema.Attribute.Required &
Schema.Attribute.SetMinMaxLength<{
minLength: 1
}>
token: Schema.Attribute.Relation<'manyToOne', 'admin::transfer-token'>
createdAt: Schema.Attribute.DateTime
updatedAt: Schema.Attribute.DateTime
publishedAt: Schema.Attribute.DateTime
createdBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
updatedBy: Schema.Attribute.Relation<'oneToOne', 'admin::user'> & Schema.Attribute.Private
locale: Schema.Attribute.String
localizations: Schema.Attribute.Relation<'oneToMany', 'admin::transfer-token-permission'>
}
}
declare module '@strapi/strapi' {
export module Public {
export interface ContentTypeSchemas {
'plugin::upload.file': PluginUploadFile
'plugin::upload.folder': PluginUploadFolder
'plugin::i18n.locale': PluginI18NLocale
'plugin::content-releases.release': PluginContentReleasesRelease
'plugin::content-releases.release-action': PluginContentReleasesReleaseAction
'plugin::review-workflows.workflow': PluginReviewWorkflowsWorkflow
'plugin::review-workflows.workflow-stage': PluginReviewWorkflowsWorkflowStage
'plugin::users-permissions.permission': PluginUsersPermissionsPermission
'plugin::users-permissions.role': PluginUsersPermissionsRole
'plugin::users-permissions.user': PluginUsersPermissionsUser
'api::category.category': ApiCategoryCategory
'api::product.product': ApiProductProduct
'api::recommend.recommend': ApiRecommendRecommend
'api::tag.tag': ApiTagTag
'admin::permission': AdminPermission
'admin::user': AdminUser
'admin::role': AdminRole
'admin::api-token': AdminApiToken
'admin::api-token-permission': AdminApiTokenPermission
'admin::transfer-token': AdminTransferToken
'admin::transfer-token-permission': AdminTransferTokenPermission
}
}
}

View File

@ -5,6 +5,8 @@ onLaunch(() => {
console.log('App Launch')
})
onShow(() => {
// tabbar
uni.hideTabBar()
console.log('App Show')
})
onHide(() => {

7
src/components/goods.vue Normal file
View File

@ -0,0 +1,7 @@
<template>
<view class=""></view>
</template>
<script lang="js" setup></script>
<style lang="scss" scoped></style>

56
src/components/tabbar.vue Normal file
View File

@ -0,0 +1,56 @@
<template>
<view
class="tab-bar flex justify-around bg-white border-t border-gray-200 pos-fixed bottom-0 w-full"
>
<view
v-for="(item, index) in tabs"
:key="index"
class="tab-item flex-1 flex flex-col items-center justify-center py-2 cursor-pointer"
@click="selectTab(item, index)"
:class="{ active: item.path === routers.routers.path }"
>
<view class="icon-wrapper relative w-6 h-6 mb-1">
<view
class="icon-svg relative z-10 w-6 h-6"
v-html="item.path === routers.routers.path ? item.activeIcon : item.icon"
></view>
</view>
<text
class="text text-xs text-center"
:class="{
'text-[#00a2ff]': item.path === routers.routers.path,
'text-gray-800': item.path !== routers.routers.path,
}"
>
{{ item.text }}
</text>
</view>
</view>
</template>
<script setup>
import { useRouterStore } from '@/store/routers'
const routers = useRouterStore()
const tabs = [
{
text: '首页',
path: '/pages/index/index',
icon: `<svg t="1728621030479" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3744" width="24" height="24"><path d="M972.631118 255.850987L565.400878 14.630378C548.928157 4.876793 530.468594 0 511.990969 0s-36.937188 4.876793-53.391847 14.630378L51.368882 255.850987A104.796853 104.796853 0 0 0 0 345.9994v573.239871c0 57.853209 46.907519 104.760729 104.760729 104.760729h814.46048c57.853209 0 104.760729-46.907519 104.760729-104.760729V345.9994a104.74086 104.74086 0 0 0-51.35082-90.148413zM950.071437 882.067275c0 37.569365-30.45286 68.022225-68.022225 68.022225H141.932725c-37.569365 0-68.022225-30.45286-68.022225-68.022225V360.774275a56.769478 56.769478 0 0 1 27.851905-48.858236L496.27686 78.227365c4.750357-2.817702 10.187078-4.298802 15.714109-4.298802 5.527032 0 10.963752 1.4811 15.714109 4.298802l394.514455 233.688674a56.791152 56.791152 0 0 1 27.833842 48.858236v521.293z" p-id="3745"></path></svg>`,
activeIcon: `<svg t="1728621030479" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3744" width="24" height="24"><path d="M972.631118 255.850987L565.400878 14.630378C548.928157 4.876793 530.468594 0 511.990969 0s-36.937188 4.876793-53.391847 14.630378L51.368882 255.850987A104.796853 104.796853 0 0 0 0 345.9994v573.239871c0 57.853209 46.907519 104.760729 104.760729 104.760729h814.46048c57.853209 0 104.760729-46.907519 104.760729-104.760729V345.9994a104.74086 104.74086 0 0 0-51.35082-90.148413zM950.071437 882.067275c0 37.569365-30.45286 68.022225-68.022225 68.022225H141.932725c-37.569365 0-68.022225-30.45286-68.022225-68.022225V360.774275a56.769478 56.769478 0 0 1 27.851905-48.858236L496.27686 78.227365c4.750357-2.817702 10.187078-4.298802 15.714109-4.298802 5.527032 0 10.963752 1.4811 15.714109 4.298802l394.514455 233.688674a56.791152 56.791152 0 0 1 27.833842 48.858236v521.293z" p-id="3745" fill="#00A2FF"></path></svg>`,
},
{
text: '商城',
path: '/pages/shop/index',
icon: `<svg t="1728621083153" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4786" width="24" height="24"><path d="M825.6 554.666667c-64 0-121.6-38.4-155.733333-89.6C633.6 516.266667 576 554.666667 512 554.666667s-121.6-38.4-155.733333-89.6C320 516.266667 264.533333 554.666667 198.4 554.666667 89.6 554.666667 0 465.066667 0 356.266667v-8.533334L151.466667 0h721.066666L1024 345.6v8.533333c0 110.933333-89.6 200.533333-198.4 200.533334z m-200.533333-219.733334h85.333333c0 61.866667 51.2 134.4 113.066667 134.4 59.733333 0 108.8-46.933333 113.066666-104.533333L817.066667 85.333333H206.933333L85.333333 364.8c4.266667 57.6 53.333333 104.533333 113.066667 104.533333 64 0 113.066667-74.666667 113.066667-134.4h85.333333c0 61.866667 51.2 134.4 113.066667 134.4 66.133333 0 115.2-74.666667 115.2-134.4zM810.666667 1021.866667H213.333333c-83.2 0-149.333333-64-149.333333-142.933334V595.2h85.333333v283.733333c0 32 27.733333 57.6 64 57.6h597.333334c34.133333 0 64-25.6 64-57.6V595.2h85.333333v283.733333c0 78.933333-66.133333 142.933333-149.333333 142.933334z" p-id="4787"></path></svg>`,
activeIcon: `<svg t="1728621083153" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4786" width="24" height="24"><path d="M825.6 554.666667c-64 0-121.6-38.4-155.733333-89.6C633.6 516.266667 576 554.666667 512 554.666667s-121.6-38.4-155.733333-89.6C320 516.266667 264.533333 554.666667 198.4 554.666667 89.6 554.666667 0 465.066667 0 356.266667v-8.533334L151.466667 0h721.066666L1024 345.6v8.533333c0 110.933333-89.6 200.533333-198.4 200.533334z m-200.533333-219.733334h85.333333c0 61.866667 51.2 134.4 113.066667 134.4 59.733333 0 108.8-46.933333 113.066666-104.533333L817.066667 85.333333H206.933333L85.333333 364.8c4.266667 57.6 53.333333 104.533333 113.066667 104.533333 64 0 113.066667-74.666667 113.066667-134.4h85.333333c0 61.866667 51.2 134.4 113.066667 134.4 66.133333 0 115.2-74.666667 115.2-134.4zM810.666667 1021.866667H213.333333c-83.2 0-149.333333-64-149.333333-142.933334V595.2h85.333333v283.733333c0 32 27.733333 57.6 64 57.6h597.333334c34.133333 0 64-25.6 64-57.6V595.2h85.333333v283.733333c0 78.933333-66.133333 142.933333-149.333333 142.933334z" p-id="4787" fill="#00A2FF"></path></svg>`,
},
]
const selectTab = (tab, index) => {
uni.switchTab({ url: tab.path })
routers.routers.path = tab.path
}
</script>
<style scoped></style>

View File

@ -32,8 +32,8 @@
{
"iconPath": "static/tabbar/example.png",
"selectedIconPath": "static/tabbar/exampleHL.png",
"pagePath": "pages/about/about",
"text": "关于"
"pagePath": "pages/shop/index",
"text": "商城"
}
]
},
@ -47,10 +47,27 @@
}
},
{
"path": "pages/about/about",
"path": "pages/product/index",
"type": "page",
"layout": "default",
"style": {
"navigationBarTitleText": "商城"
"navigationBarTitleText": "商品详情"
}
},
{
"path": "pages/search/index",
"type": "page",
"layout": "default",
"style": {
"navigationBarTitleText": "搜索页面"
}
},
{
"path": "pages/shop/index",
"type": "page",
"layout": "default",
"style": {
"navigationBarTitleText": "宇森科技软件商城"
}
}
],

View File

@ -1,36 +0,0 @@
<route lang="json5">
{
style: {
navigationBarTitleText: '商城',
},
}
</route>
<template>
<view
class="bg-white overflow-hidden pt-2 px-4"
:style="{ marginTop: safeAreaInsets?.top + 'px' }"
>
<view class="text-center text-3xl mt-8">
鸽友们好我是
<text class="text-red-500">菲鸽</text>
</view>
<RequestComp />
<UploadComp />
</view>
</template>
<script lang="ts" setup>
import RequestComp from './components/request.vue'
import UploadComp from './components/upload.vue'
//
const { safeAreaInsets } = uni.getSystemInfoSync()
</script>
<style lang="scss" scoped>
.test-css {
// mt-4=>1rem=>16px;
margin-top: 16px;
}
</style>

View File

@ -1,56 +0,0 @@
<route lang="json5">
{
layout: 'demo',
style: {
navigationBarTitleText: '请求',
},
}
</route>
<template>
<view class="p-6 text-center">
<view class="my-2">使用的是 laf 云后台</view>
<view class="text-green-400">我的推荐码可以获得佣金</view>
<!-- #ifdef H5 -->
<view class="my-2">
<a class="my-2" :href="recommendUrl" target="_blank">{{ recommendUrl }}</a>
</view>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="my-2 text-left text-sm">{{ recommendUrl }}</view>
<!-- #endif -->
<!-- http://localhost:9000/#/pages/index/request -->
<wd-button @click="run" class="my-6">发送请求</wd-button>
<view class="h-12">
<view v-if="loading">loading...</view>
<block v-else>
<view class="text-xl">请求数据如下</view>
<view class="text-green leading-8">{{ JSON.stringify(data) }}</view>
</block>
</view>
<wd-button type="error" @click="reset" class="my-6" :disabled="!data">重置数据</wd-button>
</view>
</template>
<script lang="ts" setup>
import { getFooAPI, postFooAPI, IFooItem } from '@/service/index/foo'
const recommendUrl = ref('http://laf.run/signup?code=ohaOgIX')
// const initialData = {
// name: 'initialData',
// id: '1234',
// }
const initialData = undefined
// Service
const { loading, error, data, run } = useRequest<IFooItem>(() => getFooAPI('菲鸽'), {
immediate: true,
initialData,
})
const reset = () => {
data.value = initialData
}
</script>

View File

@ -1,30 +0,0 @@
<route lang="json5" type="page">
{
layout: 'default',
style: {
navigationBarTitleText: '上传-状态一体化',
},
}
</route>
<template>
<view class="p-4 text-center">
<wd-button @click="run">选择图片并上传</wd-button>
<view v-if="loading" class="text-blue h-10">上传...</view>
<template v-else>
<view class="m-2">上传后返回的接口数据</view>
<view class="m-2">{{ data }}</view>
<view class="h-80 w-full">
<image v-if="data" :src="data || data" mode="scaleToFill" />
</view>
</template>
</view>
</template>
<script lang="ts" setup>
const { loading, data, run } = useUpload({ user: '菲鸽' })
</script>
<style lang="scss" scoped>
//
</style>

View File

@ -9,37 +9,18 @@
<template>
<view class="home-root">
<view class="container">
<!-- 左侧圆形部分 -->
<view class="circle">宇森科技</view>
<!-- 右侧矩形部分 -->
<view class="rectangle">
<text>成立历史介绍来历参与事情</text>
</view>
</view>
<image class="w-full" src="/static/index/index_bg.jpg" mode="widthFix" />
<view class="container"></view>
</view>
<Tabbar />
</template>
<script lang="js" setup>
// TODO
import Tabbar from '@/components/tabbar.vue'
</script>
<style lang="scss" scoped>
.home-root {
@apply bg-white min-h-screen flex items-center justify-center;
}
.container {
@apply flex items-center p-4;
}
.circle {
@apply w-20 h-20 rounded-full flex items-center justify-center text-center bg-blue-200 text-black;
}
.rectangle {
@apply w-60 h-20 ml-4 flex items-center justify-center text-black border rounded-lg;
border-color: #000000;
page {
background-color: #0f71f6;
}
</style>

View File

@ -0,0 +1,89 @@
<route lang="json5" type="page">
{
layout: 'default',
style: {
navigationBarTitleText: '商品详情',
},
}
</route>
<template>
<view class="p-1 bg-white">
<!-- 轮播图多张图片 -->
<view v-if="product.product_images && product.product_images.length > 0" class="swiper-container mb-4">
<swiper autoplay="true" interval="3000" class="rounded-lg">
<swiper-item @click="previewImage(index)" v-for="(image, index) in product.product_images" :key="index">
<image :src="getStrapiImage(image)" mode="aspectFit" class="w-full h-48 rounded-lg" alt="Product Image" />
</swiper-item>
</swiper>
</view>
<!-- 商品名称 -->
<view class="text-xl font-bold mb-2">{{ product.name }}</view>
<!-- 商品描述 -->
<view class="text-sm text-gray-600 mb-4">{{ product.description }}</view>
<!-- 商品分类 -->
<view v-if="product.categoryType" class="text-sm text-gray-500 mb-4">
分类: {{ product.categoryType.map(item => item.categoryName) }}
</view>
<!-- 商品标签 -->
<view class="flex gap-1">
<wd-tag v-for="tag in product.tags" :bg-color="tag.color" mark>{{ tag.tag }}</wd-tag>
</view>
<view class="pt-1" v-html="product.detail"></view>
<!-- 购买按钮 -->
<button class="w-full py-3 bg-blue-500 text-white text-center rounded-lg pos-fixed bottom-0">
联系客服
</button>
</view>
</template>
<script setup>
import { httpGet } from '@/utils/http'
import { getStrapiImage } from '@/utils/image'
// Strapi
const product = ref({})
//
function previewImage(currentIndex) {
const imageUrls = product.value.product_images.map(image => getStrapiImage(image));
uni.previewImage({
urls: imageUrls, //
current: imageUrls[currentIndex], //
});
}
//
const fetchProduct = async (id) => {
// API
const res = await httpGet(`/products/${id}?populate=*`)
product.value = res.data
}
onLoad((options) => {
if (options.id) {
fetchProduct(options.id)
} else {
uni.showToast({ icon: 'none', title: '该商品已下架' })
uni.navigateTo({ url: "/pages/shop/index" })
}
})
</script>
<style scoped>
.swiper-container {
height: 12rem;
}
page {
background-color: #F5F5F5;
}
</style>

107
src/pages/search/index.vue Normal file
View File

@ -0,0 +1,107 @@
<route lang="json5" type="page">
{
layout: 'default',
style: {
navigationBarTitleText: '搜索页面',
},
}
</route>
<template>
<!-- 展示搜索条例 -->
<wd-search class="pos-fixed top-40px w-full z-999" v-model="searchValue" cancel-txt="搜索" @search="search"
@cancel="cancel" />
<!-- 历史开发的软件 -->
<view class="flex flex-col gap-2 items-center pt-1 mt-50px pb-16">
<view v-for="product in products" :key="product.id" @click="goProduct(product)"
class="w-95vw pt-2 shadow-sm rounded-2 bg-white flex flex-col">
<image :src="getStrapiImage(product.product_image)" mode="heightFix" alt="Card Image"
class="w-full h-48 rounded-t-lg flex-auto m-auto" />
<view class="p-4">
<h2 class="text-xl font-bold mb-2 flex items-center gap-1">
{{ product.name }}
<wd-tag v-if="product.tags && product.tags.length" :bg-color="product.tags[0].color" mark>
{{ product.tags[0].tag }}
</wd-tag>
</h2>
<p class="text-gray-700 mb-4">{{ product.description }}</p>
<view class="flex gap-1">
<wd-tag v-for="tag in product.tags" :key="tag.id" :bg-color="tag.color" mark>{{ tag.tag }}</wd-tag>
</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { httpGet } from '@/utils/http';
import { getStrapiImage } from '@/utils/image';
const products = ref([]);
const searchValue = ref('');
const categoryId = ref(null);
function goProduct(p) {
uni.navigateTo({ url: `/pages/product/index?id=${p.documentId}` });
}
function search() {
if (categoryId.value) {
fetchProductsByCategory(categoryId.value);
} else {
loadSearchData(searchValue.value);
}
}
function cancel() {
if (categoryId.value) {
fetchProductsByCategory(categoryId.value);
} else {
loadSearchData(searchValue.value);
}
}
async function loadSearchData(keyword) {
try {
const res = await httpGet(
`/products?populate=*&filters[$or][0][name][$contains]=${keyword}&filters[$or][1][description][$contains]=${keyword}`
);
products.value = res.data;
} catch (error) {
console.error(error);
}
}
const fetchProductsByCategory = async (categoryId) => {
try {
let query = ''
if (searchValue.value && searchValue.value != '') {
query = `&filters[$or][0][name][$contains]=${searchValue.value}&filters[$or][1][description][$contains]=${searchValue.value}`
}
const res = await httpGet(
`/products?populate=*&filters[categoryType][id][$in]=${categoryId}${query}`
);
products.value = res.data;
} catch (error) {
console.error(error);
}
}
onLoad((options) => {
if (options.keyword) {
searchValue.value = options.keyword;
loadSearchData(searchValue.value);
} else if (options.categoryId) {
categoryId.value = options.categoryId;
fetchProductsByCategory(categoryId.value);
}
})
</script>
<style lang="scss" scoped>
page {
background-color: #F5F5F5;
}
</style>

188
src/pages/shop/index.vue Normal file
View File

@ -0,0 +1,188 @@
<route lang="json5" type="page">
{
layout: 'default',
style: {
navigationBarTitleText: '宇森科技软件商城',
},
}
</route>
<template>
<wd-search v-model="value" @search="search" @cancel="cancel" cancel-txt="搜索" />
<!-- 这里是推广图片 -->
<view class="p-2">
<wd-swiper :list="swiperList" autoplay :current="current" @click="handleClick" @change="onChange"></wd-swiper>
</view>
<!-- 下面是分类商品 -->
<view class="rounded-4 p-2">
<wd-grid :column="3">
<wd-grid-item @click="goCategory(item)" icon-size="30px" use-icon-slot v-for="item in categorys"
:text="item.categoryName">
<template #icon>
<image class="w-30px" mode="widthFix" :src="getStrapiImage(item.icon)" />
</template>
</wd-grid-item>
</wd-grid>
</view>
<!-- 推荐列表 -->
<view class="pos-relative flex gap-2 items-center overflow-hidden mt-2 pl-2">
<view class="flex transition-all gap-2" :style="{ transform: `translateX(${translateX}px)` }"
@touchstart="startDrag" @touchmove="drag" @touchend="endDrag">
<!-- 卡片1 -->
<view v-for="product in products.slice(0, 4)"
class="min-w-81vw w-81vw shadow-2xl bg-white shadow-lg rounded-lg max-w-sm p-4 flex flex-col">
<image :src="getStrapiImage(product.product_image)" mode="heightFix" alt="Card Image"
class="h-48 rounded-t-lg flex-auto m-auto" />
<view class="p-4">
<view @click="goProduct(product)" class="text-xl font-bold mb-2">{{ product.name }}</view>
<view class="text-gray-700 mb-4" v-html="product.description">
</view>
<button class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600 transition">
联系我们
</button>
</view>
</view>
</view>
</view>
<!-- 历史开发的软件 -->
<view class="flex flex-col gap-1 items-center pt-1 mt-1 pb-16">
<view @click="goProduct(product)" v-for="product in products.slice(4)"
class="w-95vw pt-2 shadow-sm rounded-2 bg-white flex flex-col">
<image :src="getStrapiImage(product.product_image)" mode="heightFix" alt="Card Image"
class="w-full h-48 rounded-t-lg flex-auto m-auto" />
<view class="p-4">
<h2 class="text-xl font-bold mb-2 flex items-center gap-1">
{{ product.name }}
<wd-tag v-if="product.tags && product.tags.length" :bg-color="product.tags[0].color" mark>{{
product.tags[0].tag
}}</wd-tag>
</h2>
<p class="text-gray-700 mb-4">{{ product.description }}</p>
<view class="flex gap-1">
<wd-tag v-for="tag in product.tags" :bg-color="tag.color" mark>{{ tag.tag }}</wd-tag>
</view>
</view>
</view>
</view>
<Tabbar />
</template>
<script lang="js" setup>
import Tabbar from '@/components/tabbar.vue'
import { httpGet } from '@/utils/http'
import { getStrapiImage } from '@/utils/image'
const value = ref('')
const current = ref(0)
const recommends = ref([])
const swiperList = ref([])
const categorys = ref([])
const products = ref([])
function goCategory(c) {
uni.navigateTo({ url: `/pages/search/index?categoryId=${c.id}` });
}
function goProduct(p) {
uni.navigateTo({ url: `/pages/product/index?id=${p.documentId}` })
}
//
async function getRecommends() {
const res = await httpGet('/recommends?populate=*')
recommends.value = res.data
recommends.value.forEach((item) => {
item.url = getStrapiImage(item.image)
console.log(item.url)
swiperList.value.push(item.url)
})
}
function search() {
uni.navigateTo({ url: '/pages/search/index?keyword=' + value.value })
}
function cancel() {
search()
}
//
async function getCategorys() {
const res = await httpGet('/categorys?populate=*')
categorys.value = res.data
}
//
async function getProducts() {
const res = await httpGet('/products?populate=*')
products.value = res.data
}
onMounted(async () => {
try {
getRecommends()
getCategorys()
getProducts()
} catch (e) {
console.log(e)
}
})
function handleClick(e) {
console.log(e)
}
function onChange(e) {
console.log(e)
}
// X
const translateX = ref(0)
//
const currentCardIndex = ref(1)
// X
const startX = ref(0)
//
const startDrag = (e) => {
startX.value = e.touches[0].clientX
}
//
const drag = (e) => {
const deltaX = e.touches[0].clientX - startX.value
translateX.value = deltaX - currentCardIndex.value * ((81 * window.innerWidth) / 100)
}
//
const endDrag = (e) => {
const deltaX = e.changedTouches[0].clientX - startX.value
const threshold = 50 //
//
if (deltaX > threshold && currentCardIndex.value > 0) {
currentCardIndex.value--
}
//
else if (deltaX < -threshold && currentCardIndex.value < 2) {
currentCardIndex.value++
}
// translateX
translateX.value = -currentCardIndex.value * ((81 * window.innerWidth) / 100)
}
</script>
<style lang="scss" scoped>
page {
background-color: #f5f5f5;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

18
src/store/routers.js Normal file
View File

@ -0,0 +1,18 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
const initState = { path: '/pages/index/index', }
export const useRouterStore = defineStore(
'routers',
() => {
const routers = ref({ ...initState })
return {
routers
}
},
{
persist: true,
},
)

View File

@ -1,7 +1,10 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
const initState = { nickname: '', avatar: '' }
const initState = {
token:
'c9f6de432ba6edb6c56d0a8d8e0feaaa8bfcf8b8d82ecf9976fd1fc2567b6f8c8f3775cfab90dd12e0124c486ed18bbd8c6ed509ee492c659c2b3b8c6bd102acc67b179095cdbc6cc1ccf79c0310f1a3be0771d29811ab88297a441107deabb493654c3297d39d60719340a4a4b82e692a99decbefd2c430d9a4c2561c0103f3',
}
export const useUserStore = defineStore(
'user',

View File

@ -5,12 +5,14 @@
interface NavigateToOptions {
url: "/pages/index/index" |
"/pages/about/about";
"/pages/product/index" |
"/pages/search/index" |
"/pages/shop/index";
}
interface RedirectToOptions extends NavigateToOptions {}
interface SwitchTabOptions {
url: "/pages/index/index" | "/pages/about/about"
url: "/pages/index/index" | "/pages/shop/index"
}
type ReLaunchOptions = NavigateToOptions | SwitchTabOptions;

28
src/utils/image.ts Normal file
View File

@ -0,0 +1,28 @@
const baseUrl = import.meta.env.VITE_STATIC_BASEURL
// 获取 Strapi 中图片的工具函数// 获取 Strapi 中图片的工具函数
export function getStrapiImage(imageData) {
try {
// 判断imageData 如果是对象且不为数组就直接返回url路径
if (typeof imageData === 'object' && !Array.isArray(imageData)) {
return baseUrl + imageData.url
}
// 确保返回的数据中包含图片信息
if (imageData && Array.isArray(imageData)) {
if (imageData.length === 1) {
console.log('imageData:', baseUrl + imageData[0].url)
// 如果只有一个图片,返回单个 URL
return baseUrl + imageData[0].url
} else {
// 如果有多个图片,返回 URL 数组
return imageData.map((image) => baseUrl + image.url)
}
} else {
throw new Error('没有找到图片数据')
}
} catch (error) {
console.error('解析图片数据失败:', error)
return null
}
}