chore: add demo profile and local api proxy
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -15,6 +15,8 @@ coverage/
|
||||
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!**/.env.example
|
||||
|
||||
backend/logs/
|
||||
deploy/.data/
|
||||
|
||||
@@ -25,6 +25,15 @@ mvn test
|
||||
- Rider H5: `http://localhost:5174`
|
||||
- Resident miniapp: open `miniapp/project.config.json` in WeChat DevTools
|
||||
|
||||
No-database demo backend:
|
||||
|
||||
```powershell
|
||||
cd backend
|
||||
mvn spring-boot:run "-Dspring-boot.run.profiles=demo"
|
||||
```
|
||||
|
||||
Demo profile URL: `http://localhost:18080`
|
||||
|
||||
Demo accounts:
|
||||
|
||||
- Admin: `admin / admin123`
|
||||
|
||||
2
admin-web/.env.example
Normal file
2
admin-web/.env.example
Normal file
@@ -0,0 +1,2 @@
|
||||
VITE_API_BASE_URL=
|
||||
VITE_API_PROXY_TARGET=http://localhost:8080
|
||||
@@ -4,6 +4,12 @@ import vue from '@vitejs/plugin-vue'
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 5173
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: process.env.VITE_API_PROXY_TARGET || 'http://localhost:8080',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
243
backend/src/main/java/com/linhelp/dev/DevDataInitializer.java
Normal file
243
backend/src/main/java/com/linhelp/dev/DevDataInitializer.java
Normal file
@@ -0,0 +1,243 @@
|
||||
package com.linhelp.dev;
|
||||
|
||||
import com.linhelp.delivery.DeliveryUserRequest;
|
||||
import com.linhelp.delivery.DeliveryUserService;
|
||||
import com.linhelp.groupbuy.GroupBuyRequest;
|
||||
import com.linhelp.groupbuy.GroupBuyResponse;
|
||||
import com.linhelp.groupbuy.GroupBuyService;
|
||||
import com.linhelp.notice.BannerRequest;
|
||||
import com.linhelp.notice.BannerService;
|
||||
import com.linhelp.notice.NoticeRequest;
|
||||
import com.linhelp.notice.NoticeResponse;
|
||||
import com.linhelp.notice.NoticeService;
|
||||
import com.linhelp.product.ProductCategoryRequest;
|
||||
import com.linhelp.product.ProductCategoryResponse;
|
||||
import com.linhelp.product.ProductRequest;
|
||||
import com.linhelp.product.ProductResponse;
|
||||
import com.linhelp.product.ProductService;
|
||||
import com.linhelp.product.ProductSkuRequest;
|
||||
import com.linhelp.secondhand.SecondGoodsRequest;
|
||||
import com.linhelp.secondhand.SecondGoodsResponse;
|
||||
import com.linhelp.secondhand.SecondGoodsService;
|
||||
import com.linhelp.user.AddressRequest;
|
||||
import com.linhelp.user.UserAddressService;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@Profile({"dev", "demo"})
|
||||
public class DevDataInitializer implements ApplicationRunner {
|
||||
private static final Long TENANT_ID = 1L;
|
||||
private static final Long COMMUNITY_ID = 1L;
|
||||
private static final Long MERCHANT_ID = 1L;
|
||||
private static final Long RIDER_USER_ID = 3L;
|
||||
private static final Long RESIDENT_USER_ID = 1000L;
|
||||
|
||||
private final ProductService productService;
|
||||
private final GroupBuyService groupBuyService;
|
||||
private final NoticeService noticeService;
|
||||
private final BannerService bannerService;
|
||||
private final SecondGoodsService secondGoodsService;
|
||||
private final DeliveryUserService deliveryUserService;
|
||||
private final UserAddressService addressService;
|
||||
|
||||
public DevDataInitializer(ProductService productService,
|
||||
GroupBuyService groupBuyService,
|
||||
NoticeService noticeService,
|
||||
BannerService bannerService,
|
||||
SecondGoodsService secondGoodsService,
|
||||
DeliveryUserService deliveryUserService,
|
||||
UserAddressService addressService) {
|
||||
this.productService = productService;
|
||||
this.groupBuyService = groupBuyService;
|
||||
this.noticeService = noticeService;
|
||||
this.bannerService = bannerService;
|
||||
this.secondGoodsService = secondGoodsService;
|
||||
this.deliveryUserService = deliveryUserService;
|
||||
this.addressService = addressService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) {
|
||||
if (!productService.listCategories(COMMUNITY_ID, false).isEmpty()) {
|
||||
return;
|
||||
}
|
||||
seedAddress();
|
||||
seedDeliveryUser();
|
||||
List<ProductCategoryResponse> categories = seedCategories();
|
||||
seedProducts(categories);
|
||||
seedGroupBuy();
|
||||
seedNotices();
|
||||
seedBanner();
|
||||
seedSecondGoods();
|
||||
}
|
||||
|
||||
private void seedAddress() {
|
||||
AddressRequest request = new AddressRequest();
|
||||
request.setTenantId(TENANT_ID);
|
||||
request.setCommunityId(COMMUNITY_ID);
|
||||
request.setContactName("示范居民");
|
||||
request.setPhone("13800001000");
|
||||
request.setBuilding("1号楼");
|
||||
request.setRoom("1201");
|
||||
request.setDetail("东门旁");
|
||||
request.setDefault(true);
|
||||
addressService.create(RESIDENT_USER_ID, request);
|
||||
}
|
||||
|
||||
private void seedDeliveryUser() {
|
||||
DeliveryUserRequest request = new DeliveryUserRequest();
|
||||
request.setTenantId(TENANT_ID);
|
||||
request.setCommunityId(COMMUNITY_ID);
|
||||
request.setUserId(RIDER_USER_ID);
|
||||
request.setName("配送员小林");
|
||||
request.setPhone("13800000003");
|
||||
request.setEnabled(true);
|
||||
deliveryUserService.create(request);
|
||||
}
|
||||
|
||||
private List<ProductCategoryResponse> seedCategories() {
|
||||
return Arrays.asList(
|
||||
createCategory("水果", 10),
|
||||
createCategory("零食", 20),
|
||||
createCategory("饮料", 30),
|
||||
createCategory("早餐", 40),
|
||||
createCategory("蔬菜", 50),
|
||||
createCategory("日用品", 60)
|
||||
);
|
||||
}
|
||||
|
||||
private ProductCategoryResponse createCategory(String name, int sortNo) {
|
||||
ProductCategoryRequest request = new ProductCategoryRequest();
|
||||
request.setTenantId(TENANT_ID);
|
||||
request.setCommunityId(COMMUNITY_ID);
|
||||
request.setName(name);
|
||||
request.setSortNo(sortNo);
|
||||
request.setEnabled(true);
|
||||
return productService.createCategory(request);
|
||||
}
|
||||
|
||||
private void seedProducts(List<ProductCategoryResponse> categories) {
|
||||
createProduct(categories.get(0).getId(), "烟台苹果", "/mock/apple.jpg", "脆甜多汁,适合家庭日常补货", "约1kg", 1290, 1590, 80);
|
||||
createProduct(categories.get(0).getId(), "海南香蕉", "/mock/banana.jpg", "当日到货,成熟度适中", "约1.5kg", 990, 1290, 70);
|
||||
createProduct(categories.get(1).getId(), "每日坚果", "/mock/nuts.jpg", "独立小包装,办公室零食", "12包", 2990, 3590, 45);
|
||||
createProduct(categories.get(1).getId(), "海苔脆片", "/mock/seaweed.jpg", "轻食小零嘴", "原味40g", 690, 890, 90);
|
||||
createProduct(categories.get(2).getId(), "鲜牛奶", "/mock/milk.jpg", "冷藏配送", "950ml", 1390, 1590, 60);
|
||||
createProduct(categories.get(2).getId(), "矿泉水", "/mock/water.jpg", "整箱可送上门", "24瓶", 2990, 3590, 30);
|
||||
createProduct(categories.get(3).getId(), "鲜肉包", "/mock/baozi.jpg", "早餐预订,次日送达", "4个", 800, 1000, 100);
|
||||
createProduct(categories.get(3).getId(), "豆浆", "/mock/soy-milk.jpg", "现磨豆浆", "300ml", 350, 500, 120);
|
||||
createProduct(categories.get(4).getId(), "上海青", "/mock/greens.jpg", "新鲜蔬菜,约500g", "约500g", 590, 790, 80);
|
||||
createProduct(categories.get(5).getId(), "抽纸三包装", "/mock/tissue.jpg", "家庭常备日用品", "3包", 1890, 2290, 55);
|
||||
}
|
||||
|
||||
private void createProduct(Long categoryId, String name, String coverUrl, String description,
|
||||
String skuName, int priceCent, int originPriceCent, int stock) {
|
||||
ProductRequest productRequest = new ProductRequest();
|
||||
productRequest.setTenantId(TENANT_ID);
|
||||
productRequest.setCommunityId(COMMUNITY_ID);
|
||||
productRequest.setMerchantId(MERCHANT_ID);
|
||||
productRequest.setCategoryId(categoryId);
|
||||
productRequest.setName(name);
|
||||
productRequest.setCoverUrl(coverUrl);
|
||||
productRequest.setDescription(description);
|
||||
productRequest.setUnitName("份");
|
||||
ProductResponse product = productService.createProduct(productRequest);
|
||||
|
||||
ProductSkuRequest skuRequest = new ProductSkuRequest();
|
||||
skuRequest.setTenantId(TENANT_ID);
|
||||
skuRequest.setCommunityId(COMMUNITY_ID);
|
||||
skuRequest.setSkuName(skuName);
|
||||
skuRequest.setPriceCent(priceCent);
|
||||
skuRequest.setOriginPriceCent(originPriceCent);
|
||||
skuRequest.setStock(stock);
|
||||
skuRequest.setEnabled(true);
|
||||
productService.addSku(product.getId(), skuRequest);
|
||||
productService.onShelf(product.getId());
|
||||
}
|
||||
|
||||
private void seedGroupBuy() {
|
||||
GroupBuyRequest request = new GroupBuyRequest();
|
||||
request.setTenantId(TENANT_ID);
|
||||
request.setCommunityId(COMMUNITY_ID);
|
||||
request.setTitle("今日团购:麒麟西瓜");
|
||||
request.setCoverUrl("/mock/watermelon.jpg");
|
||||
request.setDescription("满20份成团,晚饭前送到小区门口");
|
||||
request.setPriceCent(1990);
|
||||
request.setOriginPriceCent(2590);
|
||||
request.setStock(120);
|
||||
request.setStartTime(LocalDateTime.now().minusHours(1));
|
||||
request.setEndTime(LocalDateTime.now().plusDays(1));
|
||||
request.setPickupAddress("小区东门团购点");
|
||||
GroupBuyResponse groupBuy = groupBuyService.create(request);
|
||||
groupBuyService.start(groupBuy.getId());
|
||||
}
|
||||
|
||||
private void seedNotices() {
|
||||
NoticeResponse first = noticeService.create(notice("本周六小区便民服务日", "物业联合邻小帮提供快递代取、生活用品预订和家电检测服务。", "ACTIVITY", true));
|
||||
NoticeResponse second = noticeService.create(notice("地下车库临时清洗通知", "本周三9:00-12:00清洗地下车库,请车主提前挪车。", "PROPERTY", false));
|
||||
noticeService.publish(first.getId());
|
||||
noticeService.publish(second.getId());
|
||||
}
|
||||
|
||||
private NoticeRequest notice(String title, String content, String category, boolean pinned) {
|
||||
NoticeRequest request = new NoticeRequest();
|
||||
request.setTenantId(TENANT_ID);
|
||||
request.setCommunityId(COMMUNITY_ID);
|
||||
request.setTitle(title);
|
||||
request.setContent(content);
|
||||
request.setCategory(category);
|
||||
request.setPinned(pinned);
|
||||
return request;
|
||||
}
|
||||
|
||||
private void seedBanner() {
|
||||
BannerRequest request = new BannerRequest();
|
||||
request.setTenantId(TENANT_ID);
|
||||
request.setCommunityId(COMMUNITY_ID);
|
||||
request.setTitle("邻小帮今日到家");
|
||||
request.setImageUrl("/mock/banner-home.jpg");
|
||||
request.setLinkType("PAGE");
|
||||
request.setLinkValue("/pages/products/index");
|
||||
request.setSortNo(10);
|
||||
request.setEnabled(true);
|
||||
bannerService.create(request);
|
||||
}
|
||||
|
||||
private void seedSecondGoods() {
|
||||
SecondGoodsResponse published = secondGoodsService.create(RESIDENT_USER_ID, secondGoods(
|
||||
"九成新儿童自行车",
|
||||
12000,
|
||||
"适合5-8岁儿童,小区内可面交。",
|
||||
"母婴",
|
||||
Arrays.asList("/mock/bike.jpg")
|
||||
));
|
||||
secondGoodsService.approve(published.getId());
|
||||
secondGoodsService.create(RESIDENT_USER_ID, secondGoods(
|
||||
"闲置置物架",
|
||||
3000,
|
||||
"待后台审核的示例闲置。",
|
||||
"家居",
|
||||
Arrays.asList("/mock/shelf.jpg")
|
||||
));
|
||||
}
|
||||
|
||||
private SecondGoodsRequest secondGoods(String title, int priceCent, String description, String category, List<String> images) {
|
||||
SecondGoodsRequest request = new SecondGoodsRequest();
|
||||
request.setTenantId(TENANT_ID);
|
||||
request.setCommunityId(COMMUNITY_ID);
|
||||
request.setTitle(title);
|
||||
request.setImageUrls(images);
|
||||
request.setPriceCent(priceCent);
|
||||
request.setDescription(description);
|
||||
request.setCategory(category);
|
||||
request.setContactPhone("13800001000");
|
||||
request.setTradeMethod("FACE_TO_FACE");
|
||||
return request;
|
||||
}
|
||||
}
|
||||
23
backend/src/main/resources/application-demo.yml
Normal file
23
backend/src/main/resources/application-demo.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
spring:
|
||||
autoconfigure:
|
||||
exclude:
|
||||
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
|
||||
flyway:
|
||||
enabled: false
|
||||
|
||||
server:
|
||||
port: 18080
|
||||
|
||||
knife4j:
|
||||
enable: true
|
||||
|
||||
sa-token:
|
||||
token-name: Authorization
|
||||
timeout: 2592000
|
||||
|
||||
linhelp:
|
||||
storage:
|
||||
endpoint: http://localhost:9000
|
||||
access-key: linhelp
|
||||
secret-key: linhelp123
|
||||
bucket: linhelp
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.linhelp.dev;
|
||||
|
||||
import com.linhelp.delivery.DeliveryUserService;
|
||||
import com.linhelp.groupbuy.GroupBuyService;
|
||||
import com.linhelp.notice.BannerService;
|
||||
import com.linhelp.notice.NoticeService;
|
||||
import com.linhelp.product.ProductService;
|
||||
import com.linhelp.secondhand.SecondGoodsService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(properties = {
|
||||
"spring.flyway.enabled=false",
|
||||
"spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration"
|
||||
})
|
||||
class DevDataInitializerTests {
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
@Autowired
|
||||
private GroupBuyService groupBuyService;
|
||||
@Autowired
|
||||
private NoticeService noticeService;
|
||||
@Autowired
|
||||
private BannerService bannerService;
|
||||
@Autowired
|
||||
private SecondGoodsService secondGoodsService;
|
||||
@Autowired
|
||||
private DeliveryUserService deliveryUserService;
|
||||
|
||||
@Test
|
||||
void seedsOneCommunityDemoDataForLocalTrial() {
|
||||
assertThat(productService.listCategories(1L, true)).hasSize(6);
|
||||
assertThat(productService.listMini(1L, null)).hasSizeGreaterThanOrEqualTo(10);
|
||||
assertThat(groupBuyService.listMini(1L)).hasSize(1);
|
||||
assertThat(noticeService.listPublished(1L)).hasSize(2);
|
||||
assertThat(bannerService.listEnabled(1L)).hasSize(1);
|
||||
assertThat(secondGoodsService.listPublic(1L, null)).hasSize(1);
|
||||
assertThat(deliveryUserService.requireByUserId(3L).getName()).isEqualTo("配送员小林");
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,19 @@ Backend API: http://localhost:8080
|
||||
Knife4j docs: http://localhost:8080/doc.html
|
||||
```
|
||||
|
||||
If Docker/MySQL are not available or port `8080` is already occupied, use the no-database demo profile:
|
||||
|
||||
```powershell
|
||||
cd backend
|
||||
mvn spring-boot:run "-Dspring-boot.run.profiles=demo"
|
||||
```
|
||||
|
||||
Demo profile URL:
|
||||
|
||||
```text
|
||||
Backend API: http://localhost:18080
|
||||
```
|
||||
|
||||
Demo accounts:
|
||||
|
||||
```text
|
||||
@@ -60,6 +73,13 @@ URL:
|
||||
http://localhost:5173
|
||||
```
|
||||
|
||||
During local development, `/api` is proxied to `http://localhost:8080` by default. If the backend uses another port:
|
||||
|
||||
```powershell
|
||||
$env:VITE_API_PROXY_TARGET="http://localhost:18080"
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Start Rider H5
|
||||
|
||||
```powershell
|
||||
@@ -74,6 +94,8 @@ URL:
|
||||
http://localhost:5174
|
||||
```
|
||||
|
||||
Rider H5 uses the same `/api` dev proxy behavior as the admin web.
|
||||
|
||||
## Open Miniapp
|
||||
|
||||
Use WeChat DevTools to open:
|
||||
|
||||
@@ -8,7 +8,8 @@ function ensureToken() {
|
||||
url: app.globalData.apiBaseUrl + '/api/auth/dev-miniapp-login',
|
||||
method: 'POST',
|
||||
data: {
|
||||
username: 'resident'
|
||||
username: 'resident',
|
||||
password: 'dev'
|
||||
},
|
||||
success(res) {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300 && res.data && res.data.code === 0) {
|
||||
|
||||
2
rider-h5/.env.example
Normal file
2
rider-h5/.env.example
Normal file
@@ -0,0 +1,2 @@
|
||||
VITE_API_BASE_URL=
|
||||
VITE_API_PROXY_TARGET=http://localhost:8080
|
||||
@@ -4,6 +4,12 @@ import vue from '@vitejs/plugin-vue'
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 5174
|
||||
port: 5174,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: process.env.VITE_API_PROXY_TARGET || 'http://localhost:8080',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user