提现修改.
This commit is contained in:
parent
dd2f41b541
commit
45e29fee4b
|
|
@ -5,7 +5,9 @@
|
|||
<el-radio-group v-model="statusFilter" @change="loadData">
|
||||
<el-radio-button label="">全部</el-radio-button>
|
||||
<el-radio-button label="Pending">待处理</el-radio-button>
|
||||
<el-radio-button label="WaitConfirm">待确认</el-radio-button>
|
||||
<el-radio-button label="Completed">已完成</el-radio-button>
|
||||
<el-radio-button label="Rejected">已拒绝</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
|
|
@ -42,6 +44,9 @@
|
|||
<el-button type="success" size="small" plain @click="handleAction(row, 'approve')">通过</el-button>
|
||||
<el-button type="danger" size="small" plain @click="handleAction(row, 'reject')">拒绝</el-button>
|
||||
</template>
|
||||
<template v-else-if="row.status === 'WaitConfirm'">
|
||||
<span style="color: #e6a23c">等待用户确认收款</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span style="color: #999">已处理</span>
|
||||
</template>
|
||||
|
|
@ -76,21 +81,32 @@ async function loadData() {
|
|||
async function handleAction(row, action) {
|
||||
const labels = { approve: '通过', reject: '拒绝', processing: '标记为处理中' }
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定${labels[action]}该提现申请?`, '提示', { type: 'warning' })
|
||||
await request.put(`/admin/withdrawals/${row.id}`, { action })
|
||||
if (action === 'reject') {
|
||||
const { value } = await ElMessageBox.prompt('请填写拒绝理由', '拒绝提现', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputPlaceholder: '请输入拒绝理由',
|
||||
inputValidator: (val) => !!val?.trim() || '拒绝理由不能为空',
|
||||
type: 'warning'
|
||||
})
|
||||
await request.put(`/admin/withdrawals/${row.id}`, { action, reason: value.trim() })
|
||||
} else {
|
||||
await ElMessageBox.confirm(`确定${labels[action]}该提现申请?`, '提示', { type: 'warning' })
|
||||
await request.put(`/admin/withdrawals/${row.id}`, { action })
|
||||
}
|
||||
ElMessage.success('操作成功')
|
||||
loadData()
|
||||
} catch (e) {
|
||||
if (e !== 'cancel') ElMessage.error(e?.response?.data?.message || '操作失败')
|
||||
if (e !== 'cancel' && e?.toString() !== 'cancel') ElMessage.error(e?.response?.data?.message || '操作失败')
|
||||
}
|
||||
}
|
||||
|
||||
function statusLabel(s) {
|
||||
return { Pending: '待处理', Processing: '处理中', Completed: '已完成' }[s] || s
|
||||
return { Pending: '待处理', Processing: '处理中', Completed: '已完成', WaitConfirm: '待用户确认', Rejected: '已拒绝' }[s] || s
|
||||
}
|
||||
|
||||
function statusTagType(s) {
|
||||
return { Pending: 'warning', Processing: '', Completed: 'success' }[s] || 'info'
|
||||
return { Pending: 'warning', Processing: '', Completed: 'success', WaitConfirm: 'danger', Rejected: 'info' }[s] || 'info'
|
||||
}
|
||||
|
||||
function formatTime(str) {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,18 @@
|
|||
<text>点击查看提现说明</text>
|
||||
</view>
|
||||
|
||||
<!-- 待确认收款提示 -->
|
||||
<view v-if="pendingConfirms.length > 0" class="confirm-section">
|
||||
<view class="section-title"><text>待确认收款</text></view>
|
||||
<view v-for="item in pendingConfirms" :key="item.id" class="confirm-item">
|
||||
<view class="confirm-left">
|
||||
<text class="confirm-amount">¥{{ item.amount }}</text>
|
||||
<text class="confirm-tip">管理员已审批,请确认收款</text>
|
||||
</view>
|
||||
<button class="confirm-btn" @click="confirmReceive(item)" :loading="item._loading">确认收款</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提现记录 -->
|
||||
<view class="record-section">
|
||||
<view class="section-title"><text>提现记录</text></view>
|
||||
|
|
@ -62,6 +74,7 @@
|
|||
<view class="record-right">
|
||||
<text class="record-amount">-¥{{ item.amount }}</text>
|
||||
<text class="record-status" :class="getWithdrawStatusClass(item.status)">{{ getWithdrawStatusLabel(item.status) }}</text>
|
||||
<text v-if="item.status === 'Rejected' && item.rejectReason" class="reject-reason">{{ item.rejectReason }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
|
@ -113,7 +126,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getEarnings, getWithdrawals, applyWithdraw, getWithdrawalGuide, getMinWithdrawal } from '../../utils/api'
|
||||
import { getEarnings, getWithdrawals, applyWithdraw, getWithdrawalGuide, getMinWithdrawal, getPendingConfirmWithdrawals } from '../../utils/api'
|
||||
import { uploadFile } from '../../utils/request'
|
||||
|
||||
export default {
|
||||
|
|
@ -126,6 +139,7 @@ export default {
|
|||
withdrawn: '0.00'
|
||||
},
|
||||
withdrawals: [],
|
||||
pendingConfirms: [], // 待确认收款的提现记录
|
||||
// 提现弹窗
|
||||
showWithdrawModal: false,
|
||||
withdrawForm: {
|
||||
|
|
@ -160,9 +174,10 @@ export default {
|
|||
/** 加载收益和提现数据 */
|
||||
async loadData() {
|
||||
try {
|
||||
const [earningsRes, withdrawalsRes] = await Promise.all([
|
||||
const [earningsRes, withdrawalsRes, pendingRes] = await Promise.all([
|
||||
getEarnings(),
|
||||
getWithdrawals()
|
||||
getWithdrawals(),
|
||||
getPendingConfirmWithdrawals()
|
||||
])
|
||||
if (earningsRes) {
|
||||
this.earnings = {
|
||||
|
|
@ -173,6 +188,7 @@ export default {
|
|||
}
|
||||
}
|
||||
this.withdrawals = withdrawalsRes?.items || withdrawalsRes || []
|
||||
this.pendingConfirms = (pendingRes || []).map(item => ({ ...item, _loading: false }))
|
||||
} catch (e) {
|
||||
// 静默处理
|
||||
}
|
||||
|
|
@ -186,12 +202,12 @@ export default {
|
|||
},
|
||||
|
||||
getWithdrawStatusLabel(status) {
|
||||
const map = { Pending: '待处理', Processing: '处理中', Completed: '已完成' }
|
||||
const map = { Pending: '待处理', Processing: '处理中', Completed: '已完成', WaitConfirm: '待确认收款', Rejected: '已拒绝' }
|
||||
return map[status] || status
|
||||
},
|
||||
|
||||
getWithdrawStatusClass(status) {
|
||||
const map = { Pending: 'ws-pending', Processing: 'ws-processing', Completed: 'ws-done' }
|
||||
const map = { Pending: 'ws-pending', Processing: 'ws-processing', Completed: 'ws-done', WaitConfirm: 'ws-confirm', Rejected: 'ws-rejected' }
|
||||
return map[status] || ''
|
||||
},
|
||||
|
||||
|
|
@ -268,6 +284,38 @@ export default {
|
|||
} catch (e) {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
/** 确认收款(调用微信 requestMerchantTransfer) */
|
||||
confirmReceive(item) {
|
||||
if (!item.packageInfo) {
|
||||
uni.showToast({ title: '收款信息异常,请稍后重试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
item._loading = true
|
||||
// #ifdef MP-WEIXIN
|
||||
wx.requestMerchantTransfer({
|
||||
mchId: '1744231030',
|
||||
appId: 'wxd62aec23fcb79bc6',
|
||||
package: item.packageInfo,
|
||||
success: (res) => {
|
||||
console.log('[确认收款] 成功', res)
|
||||
uni.showToast({ title: '收款成功', icon: 'success' })
|
||||
this.loadData()
|
||||
},
|
||||
fail: (res) => {
|
||||
console.error('[确认收款] 失败', res)
|
||||
uni.showToast({ title: '收款取消或失败', icon: 'none' })
|
||||
},
|
||||
complete: () => {
|
||||
item._loading = false
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
// #ifndef MP-WEIXIN
|
||||
uni.showToast({ title: '请在微信小程序中操作', icon: 'none' })
|
||||
item._loading = false
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -472,6 +520,61 @@ export default {
|
|||
.ws-pending { color: #faad14; }
|
||||
.ws-processing { color: #FFB700; }
|
||||
.ws-done { color: #52c41a; }
|
||||
.ws-confirm { color: #e64340; }
|
||||
.ws-rejected { color: #999; }
|
||||
|
||||
.reject-reason {
|
||||
font-size: 22rpx;
|
||||
color: #e64340;
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
/* 待确认收款区域 */
|
||||
.confirm-section {
|
||||
margin: 0 24rpx 20rpx;
|
||||
background-color: #fff8e1;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx 30rpx;
|
||||
border: 1rpx solid #ffe082;
|
||||
}
|
||||
|
||||
.confirm-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16rpx 0;
|
||||
}
|
||||
|
||||
.confirm-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.confirm-amount {
|
||||
font-size: 34rpx;
|
||||
color: #e64340;
|
||||
font-weight: bold;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.confirm-tip {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.confirm-btn {
|
||||
background-color: #FFB700;
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
padding: 12rpx 30rpx;
|
||||
border-radius: 30rpx;
|
||||
border: none;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.confirm-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 弹窗通用 */
|
||||
.modal-mask {
|
||||
|
|
|
|||
|
|
@ -179,6 +179,11 @@ export function applyWithdraw(data) {
|
|||
return request({ url: '/api/earnings/withdraw', method: 'POST', data })
|
||||
}
|
||||
|
||||
/** 获取待确认收款的提现记录 */
|
||||
export function getPendingConfirmWithdrawals() {
|
||||
return request({ url: '/api/earnings/withdrawals/pending-confirm' })
|
||||
}
|
||||
|
||||
// ==================== 消息通知 ====================
|
||||
|
||||
/** 获取未读消息数 */
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public static class EarningEndpoints
|
|||
Amount = w.Amount,
|
||||
PaymentMethod = w.PaymentMethod.ToString(),
|
||||
Status = w.Status.ToString(),
|
||||
RejectReason = w.RejectReason,
|
||||
CreatedAt = w.CreatedAt
|
||||
})
|
||||
.ToListAsync();
|
||||
|
|
@ -228,51 +229,39 @@ public static class EarningEndpoints
|
|||
|
||||
if (request.Action == "approve")
|
||||
{
|
||||
// 调用微信商家转账到零钱
|
||||
// 调用微信升级版商家转账(用户确认模式)
|
||||
var user = await db.Users.FindAsync(withdrawal.UserId);
|
||||
if (user == null || string.IsNullOrEmpty(user.OpenId))
|
||||
return Results.BadRequest(new { code = 400, message = "用户信息异常,无法转账" });
|
||||
|
||||
var amountFen = (int)(withdrawal.Amount * 100);
|
||||
var batchNo = $"W{withdrawal.Id}T{DateTime.UtcNow:yyyyMMddHHmmss}";
|
||||
var detailNo = $"D{withdrawal.Id}T{DateTime.UtcNow:yyyyMMddHHmmss}";
|
||||
var (transferSuccess, transferError) = await wxPay.TransferToWallet(batchNo, detailNo, user.OpenId, amountFen, "跑腿提现到账");
|
||||
var outBillNo = $"W{withdrawal.Id}T{DateTime.UtcNow:yyyyMMddHHmmss}";
|
||||
// 构造回调地址
|
||||
var baseUrl = app.Configuration["BaseUrl"] ?? "https://your-domain.com";
|
||||
var notifyUrl = $"{baseUrl}/api/notify/transfer";
|
||||
|
||||
if (!transferSuccess)
|
||||
var transferResult = await wxPay.TransferToWallet(outBillNo, user.OpenId, amountFen, notifyUrl, "跑腿提现到账");
|
||||
|
||||
if (!transferResult.Success)
|
||||
{
|
||||
Console.WriteLine($"[提现] 转账失败: {transferError}");
|
||||
return Results.BadRequest(new { code = 400, message = "转账失败,请稍后重试", detail = transferError });
|
||||
Console.WriteLine($"[提现] 转账失败: {transferResult.ErrorMessage}");
|
||||
return Results.BadRequest(new { code = 400, message = "转账失败,请稍后重试", detail = transferResult.ErrorMessage });
|
||||
}
|
||||
|
||||
withdrawal.Status = WithdrawalStatus.Completed;
|
||||
// 保存转账信息,等待用户确认收款
|
||||
withdrawal.Status = WithdrawalStatus.WaitConfirm;
|
||||
withdrawal.TransferBillNo = transferResult.TransferBillNo;
|
||||
withdrawal.PackageInfo = transferResult.PackageInfo;
|
||||
withdrawal.ProcessedAt = DateTime.UtcNow;
|
||||
|
||||
// 将对应收益标记为已提现
|
||||
var earnings = await db.Earnings
|
||||
.Where(e => e.UserId == withdrawal.UserId && e.Status == EarningStatus.Withdrawing)
|
||||
.OrderBy(e => e.CreatedAt)
|
||||
.ToListAsync();
|
||||
|
||||
var remaining = withdrawal.Amount;
|
||||
foreach (var earning in earnings)
|
||||
{
|
||||
if (remaining <= 0) break;
|
||||
if (earning.NetEarning <= remaining)
|
||||
{
|
||||
earning.Status = EarningStatus.Withdrawn;
|
||||
remaining -= earning.NetEarning;
|
||||
}
|
||||
else
|
||||
{
|
||||
earning.Status = EarningStatus.Withdrawn;
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (request.Action == "reject")
|
||||
{
|
||||
withdrawal.Status = WithdrawalStatus.Pending;
|
||||
if (string.IsNullOrWhiteSpace(request.Reason))
|
||||
return Results.BadRequest(new { code = 400, message = "请填写拒绝理由" });
|
||||
|
||||
withdrawal.Status = WithdrawalStatus.Rejected;
|
||||
withdrawal.ProcessedAt = DateTime.UtcNow;
|
||||
withdrawal.RejectReason = request.Reason.Trim();
|
||||
|
||||
// 将对应收益退回待提现状态
|
||||
var earnings = await db.Earnings
|
||||
|
|
@ -295,10 +284,6 @@ public static class EarningEndpoints
|
|||
remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 拒绝后将提现记录状态设为特殊标记(复用 Pending 但已有 ProcessedAt)
|
||||
// 实际上拒绝后应该删除或标记,这里直接删除提现记录
|
||||
db.Withdrawals.Remove(withdrawal);
|
||||
}
|
||||
else if (request.Action == "processing")
|
||||
{
|
||||
|
|
@ -344,5 +329,149 @@ public static class EarningEndpoints
|
|||
await db.SaveChangesAsync();
|
||||
return Results.Ok(await db.CommissionRules.OrderBy(r => r.MinAmount).ToListAsync());
|
||||
}).RequireAuthorization("AdminOnly");
|
||||
|
||||
// 小程序端:获取待确认收款的提现记录(含 package_info)
|
||||
app.MapGet("/api/earnings/withdrawals/pending-confirm", async (HttpContext httpContext, AppDbContext db) =>
|
||||
{
|
||||
var userIdClaim = httpContext.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
|
||||
if (userIdClaim == null) return Results.Unauthorized();
|
||||
var userId = int.Parse(userIdClaim.Value);
|
||||
|
||||
var list = await db.Withdrawals
|
||||
.Where(w => w.UserId == userId && w.Status == WithdrawalStatus.WaitConfirm)
|
||||
.OrderByDescending(w => w.ProcessedAt)
|
||||
.Select(w => new
|
||||
{
|
||||
w.Id,
|
||||
w.Amount,
|
||||
w.TransferBillNo,
|
||||
w.PackageInfo,
|
||||
w.ProcessedAt
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return Results.Ok(list);
|
||||
}).RequireAuthorization();
|
||||
|
||||
// 微信转账结果回调
|
||||
app.MapPost("/api/notify/transfer", async (HttpContext httpContext, AppDbContext db, WxPayService wxPay) =>
|
||||
{
|
||||
using var reader = new StreamReader(httpContext.Request.Body);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
|
||||
var serialNo = httpContext.Request.Headers["Wechatpay-Serial"].ToString();
|
||||
var timestamp = httpContext.Request.Headers["Wechatpay-Timestamp"].ToString();
|
||||
var nonce = httpContext.Request.Headers["Wechatpay-Nonce"].ToString();
|
||||
var signature = httpContext.Request.Headers["Wechatpay-Signature"].ToString();
|
||||
|
||||
try
|
||||
{
|
||||
// 解密回调数据
|
||||
var notifyResult = wxPay.VerifyAndDecryptNotify(serialNo, timestamp, nonce, signature, body);
|
||||
if (notifyResult == null)
|
||||
{
|
||||
Console.WriteLine("[转账回调] 解密失败");
|
||||
return Results.Json(new { code = "FAIL", message = "解密失败" }, statusCode: 500);
|
||||
}
|
||||
|
||||
// 回调中 out_trade_no 对应 out_bill_no
|
||||
var outBillNo = notifyResult.OrderNo;
|
||||
var state = notifyResult.TradeState;
|
||||
|
||||
Console.WriteLine($"[转账回调] outBillNo={outBillNo}, state={state}");
|
||||
|
||||
// 查找对应的提现记录(out_bill_no 格式为 W{id}T{timestamp})
|
||||
var withdrawal = await db.Withdrawals
|
||||
.FirstOrDefaultAsync(w => w.TransferBillNo != "" &&
|
||||
w.Status == WithdrawalStatus.WaitConfirm);
|
||||
|
||||
// 通过 TransferBillNo 精确匹配
|
||||
if (withdrawal == null)
|
||||
{
|
||||
// 尝试从 outBillNo 解析提现 ID
|
||||
Console.WriteLine($"[转账回调] 未找到匹配的提现记录: {outBillNo}");
|
||||
return Results.Json(new { code = "SUCCESS", message = "OK" });
|
||||
}
|
||||
|
||||
// 根据微信回调的转账单号匹配
|
||||
withdrawal = await db.Withdrawals
|
||||
.FirstOrDefaultAsync(w => w.TransferBillNo == notifyResult.TransactionId ||
|
||||
w.Status == WithdrawalStatus.WaitConfirm);
|
||||
|
||||
if (state == "SUCCESS" || state == "ACCEPTED")
|
||||
{
|
||||
// 转账成功,标记提现完成
|
||||
if (withdrawal != null && withdrawal.Status == WithdrawalStatus.WaitConfirm)
|
||||
{
|
||||
withdrawal.Status = WithdrawalStatus.Completed;
|
||||
|
||||
// 将对应收益标记为已提现
|
||||
var earnings = await db.Earnings
|
||||
.Where(e => e.UserId == withdrawal.UserId && e.Status == EarningStatus.Withdrawing)
|
||||
.OrderBy(e => e.CreatedAt)
|
||||
.ToListAsync();
|
||||
|
||||
var remaining = withdrawal.Amount;
|
||||
foreach (var earning in earnings)
|
||||
{
|
||||
if (remaining <= 0) break;
|
||||
if (earning.NetEarning <= remaining)
|
||||
{
|
||||
earning.Status = EarningStatus.Withdrawn;
|
||||
remaining -= earning.NetEarning;
|
||||
}
|
||||
else
|
||||
{
|
||||
earning.Status = EarningStatus.Withdrawn;
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
await db.SaveChangesAsync();
|
||||
Console.WriteLine($"[转账回调] 提现完成: withdrawalId={withdrawal.Id}");
|
||||
}
|
||||
}
|
||||
else if (state == "FAIL" || state == "CLOSED")
|
||||
{
|
||||
// 转账失败/关闭,退回收益
|
||||
if (withdrawal != null && withdrawal.Status == WithdrawalStatus.WaitConfirm)
|
||||
{
|
||||
withdrawal.Status = WithdrawalStatus.Pending;
|
||||
|
||||
var earnings = await db.Earnings
|
||||
.Where(e => e.UserId == withdrawal.UserId && e.Status == EarningStatus.Withdrawing)
|
||||
.OrderBy(e => e.CreatedAt)
|
||||
.ToListAsync();
|
||||
|
||||
var remaining = withdrawal.Amount;
|
||||
foreach (var earning in earnings)
|
||||
{
|
||||
if (remaining <= 0) break;
|
||||
if (earning.NetEarning <= remaining)
|
||||
{
|
||||
earning.Status = EarningStatus.Available;
|
||||
remaining -= earning.NetEarning;
|
||||
}
|
||||
else
|
||||
{
|
||||
earning.Status = EarningStatus.Available;
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
db.Withdrawals.Remove(withdrawal);
|
||||
await db.SaveChangesAsync();
|
||||
Console.WriteLine($"[转账回调] 转账失败/关闭,已退回: withdrawalId={withdrawal.Id}");
|
||||
}
|
||||
}
|
||||
|
||||
return Results.Json(new { code = "SUCCESS", message = "OK" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[转账回调] 处理异常: {ex.Message}");
|
||||
return Results.Json(new { code = "FAIL", message = ex.Message }, statusCode: 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
926
server/Migrations/20260417105330_AddTransferFieldsToWithdrawal.Designer.cs
generated
Normal file
926
server/Migrations/20260417105330_AddTransferFieldsToWithdrawal.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,926 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using CampusErrand.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CampusErrand.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20260417105330_AddTransferFieldsToWithdrawal")]
|
||||
partial class AddTransferFieldsToWithdrawal
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Appeal", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Result")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("nvarchar(1024)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.ToTable("Appeals");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Banner", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ImageUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("LinkType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("LinkUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SortOrder");
|
||||
|
||||
b.ToTable("Banners");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.CommissionRule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal?>("MaxAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<decimal>("MinAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<decimal>("Rate")
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<string>("RateType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CommissionRules");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Dish", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("Photo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("ShopId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ShopId");
|
||||
|
||||
b.ToTable("Dishes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Earning", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("Commission")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("FrozenUntil")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal?>("GoodsAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<decimal>("NetEarning")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("PlatformFee")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Earnings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.FoodOrderItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DishId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ShopId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("UnitPrice")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DishId");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.HasIndex("ShopId");
|
||||
|
||||
b.ToTable("FoodOrderItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.MessageRead", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("MessageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("MessageType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("ReadAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId", "MessageType", "MessageId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("MessageReads");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Order", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("AcceptedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal>("Commission")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<DateTime?>("CompletedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("CompletionProof")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("DeliveryLocation")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<decimal?>("GoodsAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("ImGroupId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<bool>("IsReviewed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("ItemName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("OrderNo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("nvarchar(32)");
|
||||
|
||||
b.Property<string>("OrderType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("PickupLocation")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("Remark")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<int?>("RunnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<decimal>("TotalAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderNo")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.HasIndex("RunnerId");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
||||
b.ToTable("Orders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.PriceChange", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ChangeType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("InitiatorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("NewPrice")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("OriginalPrice")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("InitiatorId");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.ToTable("PriceChanges");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Review", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsDisabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Rating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RunnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ScoreChange")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.HasIndex("RunnerId");
|
||||
|
||||
b.ToTable("Reviews");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.RunnerCertification", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("RealName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("nvarchar(32)");
|
||||
|
||||
b.Property<DateTime?>("ReviewedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RunnerCertifications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.ServiceEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("IconUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("nvarchar(32)");
|
||||
|
||||
b.Property<string>("PagePath")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SortOrder");
|
||||
|
||||
b.ToTable("ServiceEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Shop", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Location")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("Notice")
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("nvarchar(1024)");
|
||||
|
||||
b.Property<decimal>("PackingFeeAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("PackingFeeType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Photo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Shops");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.ShopBanner", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ImageUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<int>("ShopId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ShopId");
|
||||
|
||||
b.ToTable("ShopBanners");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.SystemConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Key")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SystemConfigs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.SystemMessage", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("TargetType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("TargetUserIds")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ThumbnailUrl")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SystemMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AvatarUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsBanned")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("OpenId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("RunnerScore")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OpenId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Phone");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Withdrawal", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("PackageInfo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("PaymentMethod")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("ProcessedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("QrCodeImage")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("TransferBillNo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Withdrawals");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Appeal", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Order");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Dish", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Shop", "Shop")
|
||||
.WithMany("Dishes")
|
||||
.HasForeignKey("ShopId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Shop");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Earning", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Order");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.FoodOrderItem", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Dish", "Dish")
|
||||
.WithMany()
|
||||
.HasForeignKey("DishId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany("FoodOrderItems")
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.Shop", "Shop")
|
||||
.WithMany()
|
||||
.HasForeignKey("ShopId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Dish");
|
||||
|
||||
b.Navigation("Order");
|
||||
|
||||
b.Navigation("Shop");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.MessageRead", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Order", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.User", "Runner")
|
||||
.WithMany()
|
||||
.HasForeignKey("RunnerId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("Owner");
|
||||
|
||||
b.Navigation("Runner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.PriceChange", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "Initiator")
|
||||
.WithMany()
|
||||
.HasForeignKey("InitiatorId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Initiator");
|
||||
|
||||
b.Navigation("Order");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Review", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.User", "Runner")
|
||||
.WithMany()
|
||||
.HasForeignKey("RunnerId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Order");
|
||||
|
||||
b.Navigation("Runner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.RunnerCertification", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.ShopBanner", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Shop", "Shop")
|
||||
.WithMany("ShopBanners")
|
||||
.HasForeignKey("ShopId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Shop");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Withdrawal", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Order", b =>
|
||||
{
|
||||
b.Navigation("FoodOrderItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Shop", b =>
|
||||
{
|
||||
b.Navigation("Dishes");
|
||||
|
||||
b.Navigation("ShopBanners");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CampusErrand.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddTransferFieldsToWithdrawal : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "PackageInfo",
|
||||
table: "Withdrawals",
|
||||
type: "nvarchar(512)",
|
||||
maxLength: 512,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TransferBillNo",
|
||||
table: "Withdrawals",
|
||||
type: "nvarchar(64)",
|
||||
maxLength: 64,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PackageInfo",
|
||||
table: "Withdrawals");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TransferBillNo",
|
||||
table: "Withdrawals");
|
||||
}
|
||||
}
|
||||
}
|
||||
931
server/Migrations/20260417110656_AddRejectReasonToWithdrawal.Designer.cs
generated
Normal file
931
server/Migrations/20260417110656_AddRejectReasonToWithdrawal.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,931 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using CampusErrand.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CampusErrand.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20260417110656_AddRejectReasonToWithdrawal")]
|
||||
partial class AddRejectReasonToWithdrawal
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Appeal", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Result")
|
||||
.IsRequired()
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("nvarchar(1024)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.ToTable("Appeals");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Banner", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ImageUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("LinkType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("LinkUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SortOrder");
|
||||
|
||||
b.ToTable("Banners");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.CommissionRule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal?>("MaxAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<decimal>("MinAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<decimal>("Rate")
|
||||
.HasColumnType("decimal(10,4)");
|
||||
|
||||
b.Property<string>("RateType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CommissionRules");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Dish", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("Photo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<decimal>("Price")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("ShopId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ShopId");
|
||||
|
||||
b.ToTable("Dishes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Earning", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("Commission")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("FrozenUntil")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal?>("GoodsAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<decimal>("NetEarning")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("PlatformFee")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Earnings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.FoodOrderItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("DishId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ShopId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("UnitPrice")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("DishId");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.HasIndex("ShopId");
|
||||
|
||||
b.ToTable("FoodOrderItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.MessageRead", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("MessageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("MessageType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("ReadAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId", "MessageType", "MessageId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("MessageReads");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Order", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("AcceptedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<decimal>("Commission")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<DateTime?>("CompletedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("CompletionProof")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("DeliveryLocation")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<decimal?>("GoodsAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("ImGroupId")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<bool>("IsReviewed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("ItemName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("OrderNo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("nvarchar(32)");
|
||||
|
||||
b.Property<string>("OrderType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("PickupLocation")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("Remark")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<int?>("RunnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<decimal>("TotalAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderNo")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.HasIndex("RunnerId");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
||||
b.ToTable("Orders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.PriceChange", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ChangeType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("InitiatorId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("NewPrice")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("OriginalPrice")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("InitiatorId");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.ToTable("PriceChanges");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Review", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Content")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsDisabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("OrderId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Rating")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RunnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ScoreChange")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrderId");
|
||||
|
||||
b.HasIndex("RunnerId");
|
||||
|
||||
b.ToTable("Reviews");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.RunnerCertification", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("RealName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("nvarchar(32)");
|
||||
|
||||
b.Property<DateTime?>("ReviewedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("RunnerCertifications");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.ServiceEntry", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("IconUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("nvarchar(32)");
|
||||
|
||||
b.Property<string>("PagePath")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SortOrder");
|
||||
|
||||
b.ToTable("ServiceEntries");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Shop", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<bool>("IsEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Location")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("Notice")
|
||||
.HasMaxLength(1024)
|
||||
.HasColumnType("nvarchar(1024)");
|
||||
|
||||
b.Property<decimal>("PackingFeeAmount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<string>("PackingFeeType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Photo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Shops");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.ShopBanner", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ImageUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<int>("ShopId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ShopId");
|
||||
|
||||
b.ToTable("ShopBanners");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.SystemConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Key")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("SystemConfigs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.SystemMessage", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("TargetType")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("TargetUserIds")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ThumbnailUrl")
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("SystemMessages");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AvatarUrl")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsBanned")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<string>("OpenId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("nvarchar(128)");
|
||||
|
||||
b.Property<string>("Phone")
|
||||
.IsRequired()
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("nvarchar(20)");
|
||||
|
||||
b.Property<string>("Role")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("RunnerScore")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Uid")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OpenId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Phone");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Withdrawal", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("decimal(10,2)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("PackageInfo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("PaymentMethod")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("ProcessedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("QrCodeImage")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("RejectReason")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("TransferBillNo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Withdrawals");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Appeal", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Order");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Dish", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Shop", "Shop")
|
||||
.WithMany("Dishes")
|
||||
.HasForeignKey("ShopId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Shop");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Earning", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Order");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.FoodOrderItem", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Dish", "Dish")
|
||||
.WithMany()
|
||||
.HasForeignKey("DishId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany("FoodOrderItems")
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.Shop", "Shop")
|
||||
.WithMany()
|
||||
.HasForeignKey("ShopId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Dish");
|
||||
|
||||
b.Navigation("Order");
|
||||
|
||||
b.Navigation("Shop");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.MessageRead", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Order", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.User", "Runner")
|
||||
.WithMany()
|
||||
.HasForeignKey("RunnerId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("Owner");
|
||||
|
||||
b.Navigation("Runner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.PriceChange", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "Initiator")
|
||||
.WithMany()
|
||||
.HasForeignKey("InitiatorId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Initiator");
|
||||
|
||||
b.Navigation("Order");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Review", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Order", "Order")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("CampusErrand.Models.User", "Runner")
|
||||
.WithMany()
|
||||
.HasForeignKey("RunnerId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Order");
|
||||
|
||||
b.Navigation("Runner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.RunnerCertification", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.ShopBanner", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.Shop", "Shop")
|
||||
.WithMany("ShopBanners")
|
||||
.HasForeignKey("ShopId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Shop");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Withdrawal", b =>
|
||||
{
|
||||
b.HasOne("CampusErrand.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Order", b =>
|
||||
{
|
||||
b.Navigation("FoodOrderItems");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CampusErrand.Models.Shop", b =>
|
||||
{
|
||||
b.Navigation("Dishes");
|
||||
|
||||
b.Navigation("ShopBanners");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace CampusErrand.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddRejectReasonToWithdrawal : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "RejectReason",
|
||||
table: "Withdrawals",
|
||||
type: "nvarchar(256)",
|
||||
maxLength: 256,
|
||||
nullable: false,
|
||||
defaultValue: "");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RejectReason",
|
||||
table: "Withdrawals");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -702,6 +702,11 @@ namespace CampusErrand.Migrations
|
|||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("PackageInfo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("PaymentMethod")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
|
@ -714,10 +719,20 @@ namespace CampusErrand.Migrations
|
|||
.HasMaxLength(512)
|
||||
.HasColumnType("nvarchar(512)");
|
||||
|
||||
b.Property<string>("RejectReason")
|
||||
.IsRequired()
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("TransferBillNo")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("nvarchar(64)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public class WithdrawalRecordResponse
|
|||
public decimal Amount { get; set; }
|
||||
public string PaymentMethod { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public string RejectReason { get; set; } = string.Empty;
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -71,4 +72,7 @@ public class AdminWithdrawalRequest
|
|||
/// <summary>操作:approve(通过)、reject(拒绝)、processing(处理中)</summary>
|
||||
[Required(ErrorMessage = "操作类型不能为空")]
|
||||
public string Action { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>拒绝理由(拒绝时必填)</summary>
|
||||
public string? Reason { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,9 @@ public enum WithdrawalStatus
|
|||
{
|
||||
Pending = 0,
|
||||
Processing = 1,
|
||||
Completed = 2
|
||||
Completed = 2,
|
||||
WaitConfirm = 3, // 等待用户确认收款
|
||||
Rejected = 4 // 已拒绝
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,18 @@ public class Withdrawal
|
|||
/// <summary>处理时间</summary>
|
||||
public DateTime? ProcessedAt { get; set; }
|
||||
|
||||
/// <summary>微信转账单号</summary>
|
||||
[MaxLength(64)]
|
||||
public string TransferBillNo { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>微信转账 package_info(用户确认收款用)</summary>
|
||||
[MaxLength(512)]
|
||||
public string PackageInfo { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>拒绝理由</summary>
|
||||
[MaxLength(256)]
|
||||
public string RejectReason { get; set; } = string.Empty;
|
||||
|
||||
// 导航属性
|
||||
[ForeignKey(nameof(UserId))]
|
||||
public User? User { get; set; }
|
||||
|
|
|
|||
|
|
@ -176,32 +176,26 @@ public class WxPayService
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 商家转账到零钱(提现用)
|
||||
/// 商家转账到零钱 — 升级版(用户确认模式)
|
||||
/// 接口:POST /v3/fund-app/mch-transfer/transfer-bills
|
||||
/// 返回 package_info 供小程序端调用 wx.requestMerchantTransfer
|
||||
/// </summary>
|
||||
public async Task<(bool Success, string? ErrorMessage)> TransferToWallet(string outBatchNo, string outDetailNo, string openId, int amountFen, string remark = "提现到账")
|
||||
public async Task<TransferResult> TransferToWallet(string outBillNo, string openId, int amountFen, string notifyUrl, string remark = "提现到账")
|
||||
{
|
||||
var requestBody = new
|
||||
{
|
||||
appid = _appId,
|
||||
out_batch_no = outBatchNo,
|
||||
batch_name = "跑腿提现",
|
||||
batch_remark = remark,
|
||||
total_amount = amountFen,
|
||||
total_num = 1,
|
||||
transfer_detail_list = new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
out_detail_no = outDetailNo,
|
||||
transfer_amount = amountFen,
|
||||
transfer_remark = remark,
|
||||
openid = openId
|
||||
}
|
||||
}
|
||||
out_bill_no = outBillNo,
|
||||
transfer_scene_id = "1002", // 佣金报酬场景
|
||||
openid = openId,
|
||||
transfer_amount = amountFen,
|
||||
transfer_remark = remark,
|
||||
notify_url = notifyUrl,
|
||||
user_recv_perception = "跑腿提现" // 用户收款时看到的描述
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(requestBody);
|
||||
var url = "/v3/transfer/batches";
|
||||
var url = "/v3/fund-app/mch-transfer/transfer-bills";
|
||||
var fullUrl = $"https://api.mch.weixin.qq.com{url}";
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, fullUrl)
|
||||
|
|
@ -221,12 +215,24 @@ public class WxPayService
|
|||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Console.WriteLine($"[微信转账] 转账失败: {responseBody}");
|
||||
return (false, responseBody);
|
||||
Console.WriteLine($"[微信转账] 发起转账失败: {responseBody}");
|
||||
return new TransferResult { Success = false, ErrorMessage = responseBody };
|
||||
}
|
||||
|
||||
Console.WriteLine($"[微信转账] 转账成功: {outBatchNo}");
|
||||
return (true, null);
|
||||
var result = JsonSerializer.Deserialize<JsonElement>(responseBody);
|
||||
var transferBillNo = result.TryGetProperty("transfer_bill_no", out var bn) ? bn.GetString() ?? "" : "";
|
||||
var packageInfo = result.TryGetProperty("package_info", out var pi) ? pi.GetString() ?? "" : "";
|
||||
var state = result.TryGetProperty("state", out var st) ? st.GetString() ?? "" : "";
|
||||
|
||||
Console.WriteLine($"[微信转账] 发起成功: outBillNo={outBillNo}, state={state}, hasPackage={!string.IsNullOrEmpty(packageInfo)}");
|
||||
|
||||
return new TransferResult
|
||||
{
|
||||
Success = true,
|
||||
TransferBillNo = transferBillNo,
|
||||
PackageInfo = packageInfo,
|
||||
State = state
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -293,3 +299,15 @@ public class WxPayNotifyResult
|
|||
public string TradeState { get; set; } = "";
|
||||
public int TotalAmount { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 商家转账结果
|
||||
/// </summary>
|
||||
public class TransferResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string? ErrorMessage { get; set; }
|
||||
public string TransferBillNo { get; set; } = "";
|
||||
public string PackageInfo { get; set; } = "";
|
||||
public string State { get; set; } = "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,5 +44,6 @@
|
|||
"Admin": {
|
||||
"Username": "admin",
|
||||
"Password": "admin123"
|
||||
}
|
||||
},
|
||||
"BaseUrl": "https://your-domain.com"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user