diff --git a/backend/src/main/java/com/example/demo/account/AccountController.java b/backend/src/main/java/com/example/demo/account/AccountController.java new file mode 100644 index 0000000..83c0ad6 --- /dev/null +++ b/backend/src/main/java/com/example/demo/account/AccountController.java @@ -0,0 +1,65 @@ +package com.example.demo.account; + +import com.example.demo.common.AppDefaultsProperties; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api/accounts") +public class AccountController { + + private final AccountService accountService; + private final AppDefaultsProperties defaults; + + public AccountController(AccountService accountService, AppDefaultsProperties defaults) { + this.accountService = accountService; + this.defaults = defaults; + } + + @GetMapping + public ResponseEntity list(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, + @RequestParam(name = "kw", required = false) String kw, + @RequestParam(name = "status", required = false) Integer status, + @RequestParam(name = "page", defaultValue = "1") int page, + @RequestParam(name = "size", defaultValue = "50") int size) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + return ResponseEntity.ok(accountService.list(sid, kw, status == null ? 1 : status, Math.max(0, page - 1), size)); + } + + @PostMapping + public ResponseEntity create(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, + @RequestHeader(name = "X-User-Id", required = false) Long userId, + @RequestBody AccountDtos.CreateAccountRequest req) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + Long uid = (userId == null ? defaults.getUserId() : userId); + Long id = accountService.create(sid, uid, req); + java.util.Map body = new java.util.HashMap<>(); + body.put("id", id); + return ResponseEntity.ok(body); + } + + @PutMapping("/{id}") + public ResponseEntity update(@PathVariable("id") Long id, + @RequestHeader(name = "X-Shop-Id", required = false) Long shopId, + @RequestHeader(name = "X-User-Id", required = false) Long userId, + @RequestBody AccountDtos.CreateAccountRequest req) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + Long uid = (userId == null ? defaults.getUserId() : userId); + accountService.update(id, sid, uid, req); + return ResponseEntity.ok().build(); + } + + @GetMapping("/{id}/ledger") + public ResponseEntity ledger(@PathVariable("id") Long id, + @RequestHeader(name = "X-Shop-Id", required = false) Long shopId, + @RequestParam(name = "startDate", required = false) String startDate, + @RequestParam(name = "endDate", required = false) String endDate, + @RequestParam(name = "kw", required = false) String kw, + @RequestParam(name = "page", defaultValue = "1") int page, + @RequestParam(name = "size", defaultValue = "20") int size) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + return ResponseEntity.ok(accountService.ledger(id, sid, kw, Math.max(0, page-1), size, startDate, endDate)); + } +} + + diff --git a/backend/src/main/java/com/example/demo/account/AccountDtos.java b/backend/src/main/java/com/example/demo/account/AccountDtos.java new file mode 100644 index 0000000..82b678b --- /dev/null +++ b/backend/src/main/java/com/example/demo/account/AccountDtos.java @@ -0,0 +1,17 @@ +package com.example.demo.account; + +import java.math.BigDecimal; + +public class AccountDtos { + + public static class CreateAccountRequest { + public String name; + public String type; // cash, bank, alipay, wechat, other + public String bankName; + public String bankAccount; + public BigDecimal openingBalance; // 可选,创建时作为期初 + public Integer status; // 1 启用 0 停用 + } +} + + diff --git a/backend/src/main/java/com/example/demo/account/AccountService.java b/backend/src/main/java/com/example/demo/account/AccountService.java new file mode 100644 index 0000000..08c406f --- /dev/null +++ b/backend/src/main/java/com/example/demo/account/AccountService.java @@ -0,0 +1,143 @@ +package com.example.demo.account; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class AccountService { + + private final JdbcTemplate jdbcTemplate; + + public AccountService(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public Object list(Long shopId, String kw, Integer status, int page, int size) { + StringBuilder sql = new StringBuilder("SELECT id, name, type, bank_name, bank_account, balance, status FROM accounts WHERE shop_id=?"); + java.util.List ps = new java.util.ArrayList<>(); ps.add(shopId); + if (status != null) { sql.append(" AND status=?"); ps.add(status); } + if (kw != null && !kw.isBlank()) { sql.append(" AND (name LIKE ? OR bank_name LIKE ? OR bank_account LIKE ?)"); ps.add('%'+kw+'%'); ps.add('%'+kw+'%'); ps.add('%'+kw+'%'); } + sql.append(" ORDER BY id DESC LIMIT ? OFFSET ?"); ps.add(size); ps.add(page * size); + List> list = jdbcTemplate.queryForList(sql.toString(), ps.toArray()); + Map body = new HashMap<>(); + body.put("list", list); + return body; + } + + @Transactional + public Long create(Long shopId, Long userId, AccountDtos.CreateAccountRequest req) { + if (req == null || req.name == null || req.name.isBlank()) throw new IllegalArgumentException("账户名称必填"); + String type = (req.type == null || req.type.isBlank()) ? "cash" : req.type.toLowerCase(); + int status = req.status == null ? 1 : req.status; + jdbcTemplate.update("INSERT INTO accounts (shop_id,user_id,name,type,bank_name,bank_account,balance,status,created_at,updated_at) VALUES (?,?,?,?,?,?,0,?,NOW(),NOW())", + shopId, userId, req.name, type, req.bankName, req.bankAccount, status); + Long id = jdbcTemplate.queryForObject("SELECT id FROM accounts WHERE shop_id=? AND name=? ORDER BY id DESC LIMIT 1", Long.class, shopId, req.name); + + BigDecimal opening = req.openingBalance == null ? BigDecimal.ZERO : req.openingBalance.setScale(2, java.math.RoundingMode.HALF_UP); + if (opening.compareTo(BigDecimal.ZERO) != 0) { + java.sql.Timestamp now = new java.sql.Timestamp(System.currentTimeMillis()); + // other_transactions + String otType = opening.compareTo(BigDecimal.ZERO) > 0 ? "income" : "expense"; + BigDecimal amt = opening.abs(); + jdbcTemplate.update("INSERT INTO other_transactions (shop_id,user_id,type,category,counterparty_type,counterparty_id,account_id,amount,tx_time,remark,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,NOW(),NOW())", + shopId, userId, otType, "account_operation", null, null, id, amt, now, "期初余额"); + // payments + String direction = opening.compareTo(BigDecimal.ZERO) > 0 ? "in" : "out"; + jdbcTemplate.update("INSERT INTO payments (shop_id,user_id,biz_type,biz_id,account_id,direction,amount,pay_time,remark,created_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())", + shopId, userId, "other", null, id, direction, amt, now, "期初余额"); + // update balance + BigDecimal delta = opening; + jdbcTemplate.update("UPDATE accounts SET balance = balance + ?, updated_at=NOW() WHERE id=? AND shop_id=?", delta, id, shopId); + } + + return id; + } + + @Transactional + public void update(Long id, Long shopId, Long userId, AccountDtos.CreateAccountRequest req) { + StringBuilder sql = new StringBuilder("UPDATE accounts SET updated_at=NOW()"); + java.util.List ps = new java.util.ArrayList<>(); + if (req.name != null) { sql.append(", name=?"); ps.add(req.name); } + if (req.type != null) { sql.append(", type=?"); ps.add(req.type.toLowerCase()); } + if (req.bankName != null) { sql.append(", bank_name=?"); ps.add(req.bankName); } + if (req.bankAccount != null) { sql.append(", bank_account=?"); ps.add(req.bankAccount); } + if (req.status != null) { sql.append(", status=?"); ps.add(req.status); } + sql.append(" WHERE id=? AND shop_id=?"); ps.add(id); ps.add(shopId); + jdbcTemplate.update(sql.toString(), ps.toArray()); + } + + public Map ledger(Long accountId, Long shopId, String kw, int page, int size, String startDate, String endDate) { + // 汇总 + String baseCond = " shop_id=? AND account_id=?"; + java.util.List basePs = new java.util.ArrayList<>(); basePs.add(shopId); basePs.add(accountId); + java.util.function.BiFunction, java.math.BigDecimal> sum = (sql, ps) -> { + java.math.BigDecimal v = jdbcTemplate.queryForObject(sql, java.math.BigDecimal.class, ps.toArray()); + return v == null ? java.math.BigDecimal.ZERO : v; + }; + String dateStart = (startDate == null || startDate.isBlank()) ? null : startDate; + String dateEnd = (endDate == null || endDate.isBlank()) ? null : endDate; + + // opening = 截止开始日期前净额 + String payOpenSql = "SELECT COALESCE(SUM(CASE WHEN direction='in' THEN amount ELSE -amount END),0) FROM payments WHERE" + baseCond + (dateStart==null?"":" AND pay_time payOpenPs = new java.util.ArrayList<>(basePs); + if (dateStart!=null) payOpenPs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); + String otOpenSql = "SELECT COALESCE(SUM(CASE WHEN type='income' THEN amount ELSE -amount END),0) FROM other_transactions WHERE" + baseCond + (dateStart==null?"":" AND tx_time otOpenPs = new java.util.ArrayList<>(basePs); + if (dateStart!=null) otOpenPs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); + java.math.BigDecimal opening = sum.apply(payOpenSql, payOpenPs).add(sum.apply(otOpenSql, otOpenPs)); + + // 区间收入/支出(含两表) + String payRangeSql = "SELECT COALESCE(SUM(CASE WHEN direction='in' THEN amount ELSE 0 END),0), COALESCE(SUM(CASE WHEN direction='out' THEN amount ELSE 0 END),0) FROM payments WHERE" + baseCond + + (dateStart==null?"":" AND pay_time>=?") + (dateEnd==null?"":" AND pay_time<=?"); + java.util.List payRangePs = new java.util.ArrayList<>(basePs); + if (dateStart!=null) payRangePs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); + if (dateEnd!=null) payRangePs.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59")); + java.util.Map pr = jdbcTemplate.queryForMap(payRangeSql, payRangePs.toArray()); + java.math.BigDecimal payIn = (java.math.BigDecimal) pr.values().toArray()[0]; + java.math.BigDecimal payOut = (java.math.BigDecimal) pr.values().toArray()[1]; + + String otRangeSql = "SELECT COALESCE(SUM(CASE WHEN type='income' THEN amount ELSE 0 END),0), COALESCE(SUM(CASE WHEN type='expense' THEN amount ELSE 0 END),0) FROM other_transactions WHERE" + baseCond + + (dateStart==null?"":" AND tx_time>=?") + (dateEnd==null?"":" AND tx_time<=?"); + java.util.List otRangePs = new java.util.ArrayList<>(basePs); + if (dateStart!=null) otRangePs.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); + if (dateEnd!=null) otRangePs.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59")); + java.util.Map or = jdbcTemplate.queryForMap(otRangeSql, otRangePs.toArray()); + java.math.BigDecimal otIn = (java.math.BigDecimal) or.values().toArray()[0]; + java.math.BigDecimal otOut = (java.math.BigDecimal) or.values().toArray()[1]; + + java.math.BigDecimal income = payIn.add(otIn); + java.math.BigDecimal expense = payOut.add(otOut); + java.math.BigDecimal ending = opening.add(income).subtract(expense); + + // 明细列表(合并两表,按时间倒序) + String listSql = "SELECT id, biz_type AS src, pay_time AS tx_time, direction, amount, remark, biz_id, NULL AS category FROM payments WHERE" + baseCond + + (dateStart==null?"":" AND pay_time>=?") + (dateEnd==null?"":" AND pay_time<=?") + + " UNION ALL " + + "SELECT id, 'other' AS src, tx_time, CASE WHEN type='income' THEN 'in' ELSE 'out' END AS direction, amount, remark, NULL AS biz_id, category FROM other_transactions WHERE" + baseCond + + (dateStart==null?"":" AND tx_time>=?") + (dateEnd==null?"":" AND tx_time<=?") + + " ORDER BY tx_time DESC LIMIT ? OFFSET ?"; + java.util.List lp = new java.util.ArrayList<>(basePs); + if (dateStart!=null) { lp.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); } + if (dateEnd!=null) { lp.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59")); } + if (dateStart!=null) { lp.add(java.sql.Timestamp.valueOf(dateStart + " 00:00:00")); } + if (dateEnd!=null) { lp.add(java.sql.Timestamp.valueOf(dateEnd + " 23:59:59")); } + lp.add(size); lp.add(page * size); + List> list = jdbcTemplate.queryForList(listSql, lp.toArray()); + + Map resp = new HashMap<>(); + resp.put("opening", opening); + resp.put("income", income); + resp.put("expense", expense); + resp.put("ending", ending); + resp.put("list", list); + return resp; + } +} + + diff --git a/backend/src/main/java/com/example/demo/common/AccountDefaultsProperties.java b/backend/src/main/java/com/example/demo/common/AccountDefaultsProperties.java new file mode 100644 index 0000000..965af62 --- /dev/null +++ b/backend/src/main/java/com/example/demo/common/AccountDefaultsProperties.java @@ -0,0 +1,25 @@ +package com.example.demo.common; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "app.account.defaults") +public class AccountDefaultsProperties { + + private String cashName = "现金"; + private String bankName = "银行存款"; + private String wechatName = "微信"; + private String alipayName = "支付宝"; + + public String getCashName() { return cashName; } + public void setCashName(String cashName) { this.cashName = cashName; } + public String getBankName() { return bankName; } + public void setBankName(String bankName) { this.bankName = bankName; } + public String getWechatName() { return wechatName; } + public void setWechatName(String wechatName) { this.wechatName = wechatName; } + public String getAlipayName() { return alipayName; } + public void setAlipayName(String alipayName) { this.alipayName = alipayName; } +} + + diff --git a/backend/src/main/java/com/example/demo/common/AppDefaultsProperties.java b/backend/src/main/java/com/example/demo/common/AppDefaultsProperties.java index 8d9cbe2..b09d51e 100644 --- a/backend/src/main/java/com/example/demo/common/AppDefaultsProperties.java +++ b/backend/src/main/java/com/example/demo/common/AppDefaultsProperties.java @@ -10,10 +10,25 @@ public class AppDefaultsProperties { private Long shopId = 1L; private Long userId = 2L; + // 默认账户名称(可配置,避免硬编码) + private String accountCashName = "现金"; + private String accountBankName = "银行存款"; + private String accountWechatName = "微信"; + private String accountAlipayName = "支付宝"; + public Long getShopId() { return shopId; } public void setShopId(Long shopId) { this.shopId = shopId; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } + + public String getAccountCashName() { return accountCashName; } + public void setAccountCashName(String accountCashName) { this.accountCashName = accountCashName; } + public String getAccountBankName() { return accountBankName; } + public void setAccountBankName(String accountBankName) { this.accountBankName = accountBankName; } + public String getAccountWechatName() { return accountWechatName; } + public void setAccountWechatName(String accountWechatName) { this.accountWechatName = accountWechatName; } + public String getAccountAlipayName() { return accountAlipayName; } + public void setAccountAlipayName(String accountAlipayName) { this.accountAlipayName = accountAlipayName; } } diff --git a/backend/src/main/java/com/example/demo/common/FinanceController.java b/backend/src/main/java/com/example/demo/common/FinanceController.java new file mode 100644 index 0000000..38dc342 --- /dev/null +++ b/backend/src/main/java/com/example/demo/common/FinanceController.java @@ -0,0 +1,29 @@ +package com.example.demo.common; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +public class FinanceController { + + private final FinanceService financeService; + private final AppDefaultsProperties defaults; + + public FinanceController(FinanceService financeService, AppDefaultsProperties defaults) { + this.financeService = financeService; + this.defaults = defaults; + } + + @GetMapping("/api/finance/categories") + public ResponseEntity listCategories(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + Map body = financeService.getCategories(sid); + return ResponseEntity.ok(body); + } +} + + diff --git a/backend/src/main/java/com/example/demo/common/FinanceDefaultsProperties.java b/backend/src/main/java/com/example/demo/common/FinanceDefaultsProperties.java new file mode 100644 index 0000000..38797dc --- /dev/null +++ b/backend/src/main/java/com/example/demo/common/FinanceDefaultsProperties.java @@ -0,0 +1,21 @@ +package com.example.demo.common; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Component +@ConfigurationProperties(prefix = "app.finance") +public class FinanceDefaultsProperties { + + // 形如 key:label, key:label 用逗号分隔 + private String incomeCategories; + private String expenseCategories; + + public String getIncomeCategories() { return incomeCategories; } + public void setIncomeCategories(String incomeCategories) { this.incomeCategories = incomeCategories; } + + public String getExpenseCategories() { return expenseCategories; } + public void setExpenseCategories(String expenseCategories) { this.expenseCategories = expenseCategories; } +} + + diff --git a/backend/src/main/java/com/example/demo/common/FinanceService.java b/backend/src/main/java/com/example/demo/common/FinanceService.java new file mode 100644 index 0000000..e9168d0 --- /dev/null +++ b/backend/src/main/java/com/example/demo/common/FinanceService.java @@ -0,0 +1,126 @@ +package com.example.demo.common; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class FinanceService { + + private static final String PARAM_KEY = "finance.categories"; + + private final SystemParameterRepository systemParameterRepository; + private final FinanceDefaultsProperties financeDefaultsProperties; + private final javax.sql.DataSource dataSource; + private final AppDefaultsProperties appDefaults; + private final ObjectMapper objectMapper = new ObjectMapper(); + + public FinanceService(SystemParameterRepository systemParameterRepository, FinanceDefaultsProperties financeDefaultsProperties, javax.sql.DataSource dataSource, AppDefaultsProperties appDefaults) { + this.systemParameterRepository = systemParameterRepository; + this.financeDefaultsProperties = financeDefaultsProperties; + this.dataSource = dataSource; + this.appDefaults = appDefaults; + } + + public Map getCategories(Long shopId) { + Map body = new HashMap<>(); + // 0) 优先从 finance_categories 表读取(避免中文乱码/统一排序) + List> income = queryCategoriesFromTable(shopId, "income"); + List> expense = queryCategoriesFromTable(shopId, "expense"); + + // 1) 回落读取 system_parameters + try { + if (income == null || income.isEmpty() || expense == null || expense.isEmpty()) { + Optional opt = systemParameterRepository.findByShopIdAndKey(shopId, PARAM_KEY); + if (opt.isPresent()) { + String json = opt.get().getValue(); + if (json != null && !json.isBlank()) { + JsonNode root = objectMapper.readTree(json); + if (income == null || income.isEmpty()) { + JsonNode incNode = root.get("income"); + if (incNode != null && incNode.isArray()) { + income = objectMapper.convertValue(incNode, new TypeReference>>(){}); + } + } + if (expense == null || expense.isEmpty()) { + JsonNode expNode = root.get("expense"); + if (expNode != null && expNode.isArray()) { + expense = objectMapper.convertValue(expNode, new TypeReference>>(){}); + } + } + } + } + } + } catch (Exception ignored) { + // 忽略异常,回落至默认配置 + } + + // 2) 回落:应用配置 app.finance.* + if (income == null || income.isEmpty()) { + income = parsePairs(financeDefaultsProperties.getIncomeCategories()); + } + if (expense == null || expense.isEmpty()) { + expense = parsePairs(financeDefaultsProperties.getExpenseCategories()); + } + + body.put("incomeCategories", income); + body.put("expenseCategories", expense); + return body; + } + + private List> parsePairs(String pairs) { + if (pairs == null || pairs.isBlank()) return Collections.emptyList(); + return Arrays.stream(pairs.split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .map(s -> { + int idx = s.indexOf(":"); + String key = idx > 0 ? s.substring(0, idx).trim() : s.trim(); + String label = idx > 0 ? s.substring(idx + 1).trim() : key; + Map m = new HashMap<>(); + m.put("key", key); + m.put("label", label); + return m; + }) + .collect(Collectors.toList()); + } + + private List> queryCategoriesFromTable(Long shopId, String type) { + Long fallbackShopId = appDefaults == null ? 1L : (appDefaults.getShopId() == null ? 1L : appDefaults.getShopId()); + try (java.sql.Connection c = dataSource.getConnection(); + java.sql.PreparedStatement ps = c.prepareStatement( + "SELECT shop_id, `key`, label FROM finance_categories WHERE shop_id IN (?, ?) AND type=? AND status=1 " + + "ORDER BY CASE WHEN shop_id=? THEN 0 ELSE 1 END, sort_order, id")) { + ps.setLong(1, shopId); + ps.setLong(2, fallbackShopId); + ps.setString(3, type); + ps.setLong(4, shopId); + try (java.sql.ResultSet rs = ps.executeQuery()) { + java.util.Map firstByKey = new java.util.LinkedHashMap<>(); + while (rs.next()) { + String key = rs.getString(2); + String label = rs.getString(3); + if (!firstByKey.containsKey(key)) { + firstByKey.put(key, label); + } + } + java.util.List> list = new java.util.ArrayList<>(); + for (java.util.Map.Entry e : firstByKey.entrySet()) { + java.util.Map m = new java.util.HashMap<>(); + m.put("key", e.getKey()); + m.put("label", e.getValue()); + list.add(m); + } + return list; + } + } catch (Exception ignored) { + return java.util.Collections.emptyList(); + } + } +} + + diff --git a/backend/src/main/java/com/example/demo/common/RequestLoggingFilter.java b/backend/src/main/java/com/example/demo/common/RequestLoggingFilter.java new file mode 100644 index 0000000..27abcaa --- /dev/null +++ b/backend/src/main/java/com/example/demo/common/RequestLoggingFilter.java @@ -0,0 +1,50 @@ +package com.example.demo.common; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.lang.NonNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Component +public class RequestLoggingFilter extends OncePerRequestFilter { + + private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class); + + @Override + protected void doFilterInternal(@NonNull HttpServletRequest request, + @NonNull HttpServletResponse response, + @NonNull FilterChain filterChain) throws ServletException, IOException { + long start = System.currentTimeMillis(); + String method = request.getMethod(); + String uri = request.getRequestURI(); + String query = request.getQueryString(); + String shopId = request.getHeader("X-Shop-Id"); + String userId = request.getHeader("X-User-Id"); + + try { + filterChain.doFilter(request, response); + } finally { + long cost = System.currentTimeMillis() - start; + int status = response.getStatus(); + if (log.isDebugEnabled()) { + log.debug("{} {}{} | status={} cost={}ms | shopId={} userId={}", + method, + uri, + (query == null ? "" : ("?" + query)), + status, + cost, + (shopId == null ? "" : shopId), + (userId == null ? "" : userId)); + } + } + } +} + + diff --git a/backend/src/main/java/com/example/demo/common/SystemParameter.java b/backend/src/main/java/com/example/demo/common/SystemParameter.java new file mode 100644 index 0000000..7de9102 --- /dev/null +++ b/backend/src/main/java/com/example/demo/common/SystemParameter.java @@ -0,0 +1,48 @@ +package com.example.demo.common; + +import jakarta.persistence.*; +import java.time.LocalDateTime; + +@Entity +@Table(name = "system_parameters") +public class SystemParameter { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "shop_id", nullable = false) + private Long shopId; + + @Column(name = "user_id", nullable = false) + private Long userId; + + @Column(name = "`key`", nullable = false, length = 64) + private String key; + + @Column(name = "value", nullable = false, columnDefinition = "JSON") + private String value; + + @Column(name = "created_at", nullable = false) + private LocalDateTime createdAt; + + @Column(name = "updated_at", nullable = false) + private LocalDateTime updatedAt; + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + public Long getShopId() { return shopId; } + public void setShopId(Long shopId) { this.shopId = shopId; } + public Long getUserId() { return userId; } + public void setUserId(Long userId) { this.userId = userId; } + public String getKey() { return key; } + public void setKey(String key) { this.key = key; } + public String getValue() { return value; } + public void setValue(String value) { this.value = value; } + public LocalDateTime getCreatedAt() { return createdAt; } + public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } + public LocalDateTime getUpdatedAt() { return updatedAt; } + public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; } +} + + diff --git a/backend/src/main/java/com/example/demo/common/SystemParameterRepository.java b/backend/src/main/java/com/example/demo/common/SystemParameterRepository.java new file mode 100644 index 0000000..5480f8b --- /dev/null +++ b/backend/src/main/java/com/example/demo/common/SystemParameterRepository.java @@ -0,0 +1,11 @@ +package com.example.demo.common; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface SystemParameterRepository extends JpaRepository { + Optional findByShopIdAndKey(Long shopId, String key); +} + + diff --git a/backend/src/main/java/com/example/demo/order/OrderController.java b/backend/src/main/java/com/example/demo/order/OrderController.java index 28b99ee..ec0aaf7 100644 --- a/backend/src/main/java/com/example/demo/order/OrderController.java +++ b/backend/src/main/java/com/example/demo/order/OrderController.java @@ -60,6 +60,13 @@ public class OrderController { return ResponseEntity.ok(orderService.list(sid, biz, type, kw, Math.max(0, page-1), size, startDate, endDate)); } + @GetMapping("/orders/{id}") + public ResponseEntity getOrderDetail(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, + @PathVariable("id") Long id) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + return ResponseEntity.ok(orderService.getSalesOrderDetail(sid, id)); + } + // 兼容前端直接调用 /api/purchase-orders @GetMapping("/purchase-orders") public ResponseEntity purchaseOrders(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, @@ -74,6 +81,13 @@ public class OrderController { return ResponseEntity.ok(orderService.list(sid, "purchase", type, kw, Math.max(0, page-1), size, startDate, endDate)); } + @GetMapping("/purchase-orders/{id}") + public ResponseEntity getPurchaseOrderDetail(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, + @PathVariable("id") Long id) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + return ResponseEntity.ok(orderService.getPurchaseOrderDetail(sid, id)); + } + @GetMapping("/payments") public ResponseEntity listPayments(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, @RequestParam(name = "direction", required = false) String direction, @@ -101,6 +115,15 @@ public class OrderController { return ResponseEntity.ok(orderService.listOtherTransactions(sid, type, accountId, kw, Math.max(0, page-1), size, startDate, endDate)); } + @PostMapping("/other-transactions") + public ResponseEntity createOtherTransaction(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, + @RequestHeader(name = "X-User-Id", required = false) Long userId, + @RequestBody OrderDtos.CreateOtherTransactionRequest req) { + Long sid = (shopId == null ? defaults.getShopId() : shopId); + Long uid = (userId == null ? defaults.getUserId() : userId); + return ResponseEntity.ok(orderService.createOtherTransaction(sid, uid, req)); + } + @GetMapping("/inventories/logs") public ResponseEntity listInventoryLogs(@RequestHeader(name = "X-Shop-Id", required = false) Long shopId, @RequestParam(name = "productId", required = false) Long productId, diff --git a/backend/src/main/java/com/example/demo/order/OrderService.java b/backend/src/main/java/com/example/demo/order/OrderService.java index 1739265..85bc3d5 100644 --- a/backend/src/main/java/com/example/demo/order/OrderService.java +++ b/backend/src/main/java/com/example/demo/order/OrderService.java @@ -1,5 +1,6 @@ package com.example.demo.order; +import com.example.demo.common.AccountDefaultsProperties; import com.example.demo.order.dto.OrderDtos; import com.example.demo.product.entity.Inventory; import com.example.demo.product.repo.InventoryRepository; @@ -18,14 +19,15 @@ import java.util.List; public class OrderService { private final InventoryRepository inventoryRepository; - - + private final AccountDefaultsProperties accountDefaults; private final JdbcTemplate jdbcTemplate; public OrderService(InventoryRepository inventoryRepository, - JdbcTemplate jdbcTemplate) { + JdbcTemplate jdbcTemplate, + AccountDefaultsProperties accountDefaults) { this.inventoryRepository = inventoryRepository; this.jdbcTemplate = jdbcTemplate; + this.accountDefaults = accountDefaults; } @Transactional @@ -163,6 +165,10 @@ public class OrderService { if (req == null) return new OrderDtos.CreatePaymentsResponse(ids); String direction = "sale".equals(bizType) ? "in" : "out"; for (OrderDtos.PaymentItem p : req) { + // 收/付款必须绑定订单(资金类不在此接口中处理) + if (("sale".equals(bizType) || "purchase".equals(bizType)) && p.orderId == null) { + throw new IllegalArgumentException("收/付款必须绑定订单"); + } Long accountId = resolveAccountId(shopId, userId, p.method); KeyHolder kh = new GeneratedKeyHolder(); String sql = "INSERT INTO payments (shop_id,user_id,biz_type,biz_id,account_id,direction,amount,pay_time,remark,created_at) " + @@ -247,39 +253,56 @@ public class OrderService { } public java.util.Map list(Long shopId, String biz, String type, String kw, int page, int size, String startDate, String endDate) { - String headTable; - if ("sale".equals(biz)) { - headTable = ("sale.return".equals(type) ? "sales_return_orders" : "sales_orders"); - } else if ("purchase".equals(biz)) { - headTable = ("purchase.return".equals(type) ? "purchase_orders" : "purchase_orders"); - } else { - // 若未传,默认销售出货 - headTable = "sales_orders"; - } - StringBuilder sql = new StringBuilder("SELECT id, order_no, order_time, amount FROM " + headTable + " WHERE shop_id=?"); + StringBuilder sql = new StringBuilder(); java.util.List ps = new java.util.ArrayList<>(); ps.add(shopId); - if ("purchase".equals(biz) && "purchase.return".equals(type)) { - sql.append(" AND status='returned'"); + + if ("purchase".equals(biz)) { + // 进货单(含退货按状态过滤),返回驼峰并带供应商名称 + sql.append("SELECT po.id, po.order_no AS orderNo, po.order_time AS orderTime, po.amount, s.name AS supplierName,\n") + .append("CASE WHEN po.status='returned' THEN 'purchase.return' ELSE 'purchase.in' END AS docType\n") + .append("FROM purchase_orders po\n") + .append("LEFT JOIN suppliers s ON s.id = po.supplier_id\n") + .append("WHERE po.shop_id=?"); + if ("purchase.return".equals(type)) { + sql.append(" AND po.status='returned'"); + } + if (kw != null && !kw.isBlank()) { sql.append(" AND (po.order_no LIKE ?)"); ps.add('%' + kw + '%'); } + if (startDate != null && !startDate.isBlank()) { sql.append(" AND po.order_time>=?"); ps.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sql.append(" AND po.order_time<=?"); ps.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + sql.append(" ORDER BY po.order_time DESC LIMIT ? OFFSET ?"); + } else { // 默认销售 + // 销售单,返回驼峰并带客户名称 + sql.append("SELECT so.id, so.order_no AS orderNo, so.order_time AS orderTime, so.amount, c.name AS customerName, 'sale.out' AS docType\n") + .append("FROM sales_orders so\n") + .append("LEFT JOIN customers c ON c.id = so.customer_id\n") + .append("WHERE so.shop_id=?"); + if (kw != null && !kw.isBlank()) { sql.append(" AND (so.order_no LIKE ?)"); ps.add('%' + kw + '%'); } + if (startDate != null && !startDate.isBlank()) { sql.append(" AND so.order_time>=?"); ps.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sql.append(" AND so.order_time<=?"); ps.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + sql.append(" ORDER BY so.order_time DESC LIMIT ? OFFSET ?"); } - if (kw != null && !kw.isBlank()) { - sql.append(" AND (order_no LIKE ?)"); - ps.add('%' + kw + '%'); - } - if (startDate != null && !startDate.isBlank()) { sql.append(" AND order_time>=?"); ps.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } - if (endDate != null && !endDate.isBlank()) { sql.append(" AND order_time<=?"); ps.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } - sql.append(" ORDER BY order_time DESC LIMIT ? OFFSET ?"); + ps.add(size); ps.add(page * size); java.util.List> list = jdbcTemplate.queryForList(sql.toString(), ps.toArray()); + // 汇总 - StringBuilder sumSql = new StringBuilder("SELECT COALESCE(SUM(amount),0) FROM " + headTable + " WHERE shop_id=?"); + StringBuilder sumSql; java.util.List sumPs = new java.util.ArrayList<>(); sumPs.add(shopId); - if ("purchase".equals(biz) && "purchase.return".equals(type)) { sumSql.append(" AND status='returned'"); } - if (kw != null && !kw.isBlank()) { sumSql.append(" AND (order_no LIKE ?)"); sumPs.add('%' + kw + '%'); } - if (startDate != null && !startDate.isBlank()) { sumSql.append(" AND order_time>=?"); sumPs.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } - if (endDate != null && !endDate.isBlank()) { sumSql.append(" AND order_time<=?"); sumPs.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + if ("purchase".equals(biz)) { + sumSql = new StringBuilder("SELECT COALESCE(SUM(amount),0) FROM purchase_orders WHERE shop_id=?"); + if ("purchase.return".equals(type)) { sumSql.append(" AND status='returned'"); } + if (kw != null && !kw.isBlank()) { sumSql.append(" AND (order_no LIKE ?)"); sumPs.add('%' + kw + '%'); } + if (startDate != null && !startDate.isBlank()) { sumSql.append(" AND order_time>=?"); sumPs.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sumSql.append(" AND order_time<=?"); sumPs.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + } else { + sumSql = new StringBuilder("SELECT COALESCE(SUM(amount),0) FROM sales_orders WHERE shop_id=?"); + if (kw != null && !kw.isBlank()) { sumSql.append(" AND (order_no LIKE ?)"); sumPs.add('%' + kw + '%'); } + if (startDate != null && !startDate.isBlank()) { sumSql.append(" AND order_time>=?"); sumPs.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sumSql.append(" AND order_time<=?"); sumPs.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + } java.math.BigDecimal total = jdbcTemplate.queryForObject(sumSql.toString(), java.math.BigDecimal.class, sumPs.toArray()); java.util.Map resp = new java.util.HashMap<>(); resp.put("list", list); @@ -288,53 +311,132 @@ public class OrderService { } public java.util.Map listPayments(Long shopId, String direction, String bizType, Long accountId, String kw, int page, int size, String startDate, String endDate) { - StringBuilder sql = new StringBuilder("SELECT id, biz_type, account_id, direction, amount, pay_time FROM payments WHERE shop_id=?"); + StringBuilder sql = new StringBuilder("SELECT p.id, p.biz_type AS bizType, p.account_id, a.name AS accountName, p.direction, p.amount, p.pay_time AS orderTime,\n" + + "CASE \n" + + " WHEN p.biz_type='sale' AND p.direction='in' THEN 'sale.collect' \n" + + " WHEN p.biz_type='purchase' AND p.direction='out' THEN 'purchase.pay' \n" + + " WHEN p.biz_type='other' AND p.direction='in' THEN 'other.income' \n" + + " WHEN p.biz_type='other' AND p.direction='out' THEN 'other.expense' \n" + + " ELSE CONCAT(p.biz_type, '.', p.direction) END AS docType\n" + + "FROM payments p LEFT JOIN accounts a ON a.id=p.account_id WHERE p.shop_id=?"); java.util.List ps = new java.util.ArrayList<>(); ps.add(shopId); - if (direction != null && !direction.isBlank()) { sql.append(" AND direction=?"); ps.add(direction); } - if (bizType != null && !bizType.isBlank()) { sql.append(" AND biz_type=?"); ps.add(bizType); } - if (accountId != null) { sql.append(" AND account_id=?"); ps.add(accountId); } - if (kw != null && !kw.isBlank()) { sql.append(" AND (CAST(id AS CHAR) LIKE ?)"); ps.add('%'+kw+'%'); } - if (startDate != null && !startDate.isBlank()) { sql.append(" AND pay_time>=?"); ps.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } - if (endDate != null && !endDate.isBlank()) { sql.append(" AND pay_time<=?"); ps.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } - sql.append(" ORDER BY pay_time DESC LIMIT ? OFFSET ?"); + if (direction != null && !direction.isBlank()) { sql.append(" AND p.direction=?"); ps.add(direction); } + if (bizType != null && !bizType.isBlank()) { sql.append(" AND p.biz_type=?"); ps.add(bizType); } + if (accountId != null) { sql.append(" AND p.account_id=?"); ps.add(accountId); } + if (kw != null && !kw.isBlank()) { sql.append(" AND (CAST(p.id AS CHAR) LIKE ?)"); ps.add('%'+kw+'%'); } + if (startDate != null && !startDate.isBlank()) { sql.append(" AND p.pay_time>=?"); ps.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sql.append(" AND p.pay_time<=?"); ps.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + sql.append(" ORDER BY p.pay_time DESC LIMIT ? OFFSET ?"); ps.add(size); ps.add(page * size); java.util.List> list = jdbcTemplate.queryForList(sql.toString(), ps.toArray()); - StringBuilder sumSql = new StringBuilder("SELECT COALESCE(SUM(amount),0) FROM payments WHERE shop_id=?"); + StringBuilder sumSql = new StringBuilder("SELECT COALESCE(SUM(p.amount),0) FROM payments p WHERE p.shop_id=?"); java.util.List sumPs = new java.util.ArrayList<>(); sumPs.add(shopId); - if (direction != null && !direction.isBlank()) { sumSql.append(" AND direction=?"); sumPs.add(direction); } - if (bizType != null && !bizType.isBlank()) { sumSql.append(" AND biz_type=?"); sumPs.add(bizType); } - if (accountId != null) { sumSql.append(" AND account_id=?"); sumPs.add(accountId); } - if (kw != null && !kw.isBlank()) { sumSql.append(" AND (CAST(id AS CHAR) LIKE ?)"); sumPs.add('%'+kw+'%'); } - if (startDate != null && !startDate.isBlank()) { sumSql.append(" AND pay_time>=?"); sumPs.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } - if (endDate != null && !endDate.isBlank()) { sumSql.append(" AND pay_time<=?"); sumPs.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + if (direction != null && !direction.isBlank()) { sumSql.append(" AND p.direction=?"); sumPs.add(direction); } + if (bizType != null && !bizType.isBlank()) { sumSql.append(" AND p.biz_type=?"); sumPs.add(bizType); } + if (accountId != null) { sumSql.append(" AND p.account_id=?"); sumPs.add(accountId); } + if (kw != null && !kw.isBlank()) { sumSql.append(" AND (CAST(p.id AS CHAR) LIKE ?)"); sumPs.add('%'+kw+'%'); } + if (startDate != null && !startDate.isBlank()) { sumSql.append(" AND p.pay_time>=?"); sumPs.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sumSql.append(" AND p.pay_time<=?"); sumPs.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } java.math.BigDecimal total = jdbcTemplate.queryForObject(sumSql.toString(), java.math.BigDecimal.class, sumPs.toArray()); java.util.Map resp = new java.util.HashMap<>(); resp.put("list", list); resp.put("totalAmount", total == null ? java.math.BigDecimal.ZERO : total); return resp; } public java.util.Map listOtherTransactions(Long shopId, String type, Long accountId, String kw, int page, int size, String startDate, String endDate) { - StringBuilder sql = new StringBuilder("SELECT id, `type`, account_id, amount, tx_time, remark FROM other_transactions WHERE shop_id=?"); + StringBuilder sql = new StringBuilder("SELECT ot.id, ot.`type`, CONCAT('other.', ot.`type`) AS docType, ot.account_id, a.name AS accountName, ot.amount, ot.tx_time AS txTime, ot.remark FROM other_transactions ot LEFT JOIN accounts a ON a.id=ot.account_id WHERE ot.shop_id=?"); java.util.List ps = new java.util.ArrayList<>(); ps.add(shopId); - if (type != null && !type.isBlank()) { sql.append(" AND `type`=?"); ps.add(type); } - if (accountId != null) { sql.append(" AND account_id=?"); ps.add(accountId); } - if (kw != null && !kw.isBlank()) { sql.append(" AND (remark LIKE ? OR category LIKE ?)"); ps.add('%'+kw+'%'); ps.add('%'+kw+'%'); } - if (startDate != null && !startDate.isBlank()) { sql.append(" AND tx_time>=?"); ps.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } - if (endDate != null && !endDate.isBlank()) { sql.append(" AND tx_time<=?"); ps.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } - sql.append(" ORDER BY tx_time DESC LIMIT ? OFFSET ?"); ps.add(size); ps.add(page * size); + if (type != null && !type.isBlank()) { sql.append(" AND ot.`type`=?"); ps.add(type); } + if (accountId != null) { sql.append(" AND ot.account_id=?"); ps.add(accountId); } + if (kw != null && !kw.isBlank()) { sql.append(" AND (ot.remark LIKE ? OR ot.category LIKE ?)"); ps.add('%'+kw+'%'); ps.add('%'+kw+'%'); } + if (startDate != null && !startDate.isBlank()) { sql.append(" AND ot.tx_time>=?"); ps.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sql.append(" AND ot.tx_time<=?"); ps.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + sql.append(" ORDER BY ot.tx_time DESC LIMIT ? OFFSET ?"); ps.add(size); ps.add(page * size); java.util.List> list = jdbcTemplate.queryForList(sql.toString(), ps.toArray()); - StringBuilder sumSql = new StringBuilder("SELECT COALESCE(SUM(amount),0) FROM other_transactions WHERE shop_id=?"); + StringBuilder sumSql = new StringBuilder("SELECT COALESCE(SUM(ot.amount),0) FROM other_transactions ot WHERE ot.shop_id=?"); java.util.List sumPs = new java.util.ArrayList<>(); sumPs.add(shopId); - if (type != null && !type.isBlank()) { sumSql.append(" AND `type`=?"); sumPs.add(type); } - if (accountId != null) { sumSql.append(" AND account_id=?"); sumPs.add(accountId); } - if (kw != null && !kw.isBlank()) { sumSql.append(" AND (remark LIKE ? OR category LIKE ?)"); sumPs.add('%'+kw+'%'); sumPs.add('%'+kw+'%'); } - if (startDate != null && !startDate.isBlank()) { sumSql.append(" AND tx_time>=?"); sumPs.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } - if (endDate != null && !endDate.isBlank()) { sumSql.append(" AND tx_time<=?"); sumPs.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } + if (type != null && !type.isBlank()) { sumSql.append(" AND ot.`type`=?"); sumPs.add(type); } + if (accountId != null) { sumSql.append(" AND ot.account_id=?"); sumPs.add(accountId); } + if (kw != null && !kw.isBlank()) { sumSql.append(" AND (ot.remark LIKE ? OR ot.category LIKE ?)"); sumPs.add('%'+kw+'%'); sumPs.add('%'+kw+'%'); } + if (startDate != null && !startDate.isBlank()) { sumSql.append(" AND ot.tx_time>=?"); sumPs.add(java.sql.Timestamp.valueOf(startDate + " 00:00:00")); } + if (endDate != null && !endDate.isBlank()) { sumSql.append(" AND ot.tx_time<=?"); sumPs.add(java.sql.Timestamp.valueOf(endDate + " 23:59:59")); } java.math.BigDecimal total = jdbcTemplate.queryForObject(sumSql.toString(), java.math.BigDecimal.class, sumPs.toArray()); java.util.Map resp = new java.util.HashMap<>(); resp.put("list", list); resp.put("totalAmount", total == null ? java.math.BigDecimal.ZERO : total); return resp; } + @org.springframework.transaction.annotation.Transactional + public java.util.Map createOtherTransaction(Long shopId, Long userId, OrderDtos.CreateOtherTransactionRequest req) { + if (req == null) throw new IllegalArgumentException("请求为空"); + String type = req.type == null ? null : req.type.trim().toLowerCase(); + if (!"income".equals(type) && !"expense".equals(type)) throw new IllegalArgumentException("type 仅支持 income/expense"); + if (req.accountId == null) throw new IllegalArgumentException("账户必选"); + java.math.BigDecimal amt = n(req.amount); + if (amt.compareTo(java.math.BigDecimal.ZERO) <= 0) throw new IllegalArgumentException("金额需大于0"); + java.time.LocalDateTime when; + if (req.txTime == null || req.txTime.isBlank()) when = nowUtc(); + else { + // 允许 yyyy-MM-dd 或完整时间 + try { + if (req.txTime.length() == 10) when = java.time.LocalDate.parse(req.txTime).atStartOfDay(); + else when = java.time.LocalDateTime.parse(req.txTime); + } catch (Exception e) { when = nowUtc(); } + } + final java.sql.Timestamp whenTs = java.sql.Timestamp.from(when.atZone(java.time.ZoneOffset.UTC).toInstant()); + + // 插入 other_transactions + org.springframework.jdbc.support.GeneratedKeyHolder kh = new org.springframework.jdbc.support.GeneratedKeyHolder(); + String sql = "INSERT INTO other_transactions (shop_id,user_id,`type`,category,counterparty_type,counterparty_id,account_id,amount,tx_time,remark,created_at,updated_at) " + + "VALUES (?,?,?,?,?,?,?,?,?, ?, NOW(), NOW())"; + jdbcTemplate.update(con -> { + java.sql.PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); + int i = 1; + ps.setLong(i++, shopId); + ps.setLong(i++, userId); + ps.setString(i++, type); + ps.setString(i++, req.category); + if (req.counterpartyType == null) ps.setNull(i++, java.sql.Types.VARCHAR); else ps.setString(i++, req.counterpartyType); + if (req.counterpartyId == null) ps.setNull(i++, java.sql.Types.BIGINT); else ps.setLong(i++, req.counterpartyId); + ps.setLong(i++, req.accountId); + ps.setBigDecimal(i++, scale2(amt)); + ps.setTimestamp(i++, whenTs); + ps.setString(i, req.remark); + return ps; + }, kh); + Number key = kh.getKey(); + Long id = key == null ? null : key.longValue(); + + // 写支付流水,联动账户余额 + String direction = "income".equals(type) ? "in" : "out"; + org.springframework.jdbc.support.GeneratedKeyHolder payKh = new org.springframework.jdbc.support.GeneratedKeyHolder(); + final Long idForPayment = id; + jdbcTemplate.update(con -> { + java.sql.PreparedStatement ps = con.prepareStatement( + "INSERT INTO payments (shop_id,user_id,biz_type,biz_id,account_id,direction,amount,pay_time,remark,created_at) VALUES (?,?,?,?,?,?,?,?,?,NOW())", + new String[]{"id"} + ); + int i = 1; + ps.setLong(i++, shopId); + ps.setLong(i++, userId); + ps.setString(i++, "other"); + if (idForPayment == null) ps.setNull(i++, java.sql.Types.BIGINT); else ps.setLong(i++, idForPayment); + ps.setLong(i++, req.accountId); + ps.setString(i++, direction); + ps.setBigDecimal(i++, scale2(amt)); + ps.setTimestamp(i++, whenTs); + ps.setString(i, req.remark); + return ps; + }, payKh); + + // 联动账户余额:收入加,支出减 + java.math.BigDecimal delta = "income".equals(type) ? amt : amt.negate(); + jdbcTemplate.update("UPDATE accounts SET balance = balance + ?, updated_at=NOW() WHERE id=? AND shop_id=?", scale2(delta), req.accountId, shopId); + + java.util.Map resp = new java.util.HashMap<>(); + resp.put("id", id); + return resp; + } + public java.util.Map listInventoryLogs(Long shopId, Long productId, String reason, String kw, int page, int size, String startDate, String endDate) { - StringBuilder sql = new StringBuilder("SELECT id, product_id, qty_delta, amount_delta, reason, tx_time FROM inventory_movements WHERE shop_id=?"); + StringBuilder sql = new StringBuilder("SELECT id, product_id, qty_delta, amount_delta, COALESCE(amount_delta,0) AS amount, reason, tx_time AS txTime, remark FROM inventory_movements WHERE shop_id=?"); java.util.List ps = new java.util.ArrayList<>(); ps.add(shopId); if (productId != null) { sql.append(" AND product_id=?"); ps.add(productId); } if (reason != null && !reason.isBlank()) { sql.append(" AND reason=?"); ps.add(reason); } @@ -354,6 +456,50 @@ public class OrderService { java.util.Map resp = new java.util.HashMap<>(); resp.put("list", list); resp.put("totalAmount", total == null ? java.math.BigDecimal.ZERO : total); return resp; } + // 详情:销售单 + public java.util.Map getSalesOrderDetail(Long shopId, Long id) { + java.util.List> heads = jdbcTemplate.queryForList( + "SELECT so.id, so.order_no AS orderNo, so.order_time AS orderTime, so.status, so.amount, so.paid_amount AS paidAmount, so.customer_id AS customerId, c.name AS customerName, so.remark\n" + + "FROM sales_orders so LEFT JOIN customers c ON c.id=so.customer_id WHERE so.shop_id=? AND so.id=?", + shopId, id); + if (heads.isEmpty()) return java.util.Map.of(); + java.util.Map head = heads.get(0); + java.util.List> items = jdbcTemplate.queryForList( + "SELECT i.id, i.product_id AS productId, p.name, p.spec, i.quantity, i.unit_price AS unitPrice, i.discount_rate AS discountRate, i.amount\n" + + "FROM sales_order_items i JOIN products p ON p.id=i.product_id WHERE i.order_id=?", + id); + java.util.List> pays = jdbcTemplate.queryForList( + "SELECT p.id, p.amount, p.pay_time AS payTime, p.account_id AS accountId, a.name AS accountName, p.direction\n" + + "FROM payments p LEFT JOIN accounts a ON a.id=p.account_id WHERE p.biz_type='sale' AND p.biz_id=?", + id); + java.util.Map resp = new java.util.HashMap<>(head); + resp.put("items", items); + resp.put("payments", pays); + return resp; + } + + // 详情:进货单 + public java.util.Map getPurchaseOrderDetail(Long shopId, Long id) { + java.util.List> heads = jdbcTemplate.queryForList( + "SELECT po.id, po.order_no AS orderNo, po.order_time AS orderTime, po.status, po.amount, po.paid_amount AS paidAmount, po.supplier_id AS supplierId, s.name AS supplierName, po.remark\n" + + "FROM purchase_orders po LEFT JOIN suppliers s ON s.id=po.supplier_id WHERE po.shop_id=? AND po.id=?", + shopId, id); + if (heads.isEmpty()) return java.util.Map.of(); + java.util.Map head = heads.get(0); + java.util.List> items = jdbcTemplate.queryForList( + "SELECT i.id, i.product_id AS productId, p.name, p.spec, i.quantity, i.unit_price AS unitPrice, i.amount\n" + + "FROM purchase_order_items i JOIN products p ON p.id=i.product_id WHERE i.order_id=?", + id); + java.util.List> pays = jdbcTemplate.queryForList( + "SELECT p.id, p.amount, p.pay_time AS payTime, p.account_id AS accountId, a.name AS accountName, p.direction\n" + + "FROM payments p LEFT JOIN accounts a ON a.id=p.account_id WHERE p.biz_type='purchase' AND p.biz_id=?", + id); + java.util.Map resp = new java.util.HashMap<>(head); + resp.put("items", items); + resp.put("payments", pays); + return resp; + } + private static BigDecimal n(BigDecimal v) { return v == null ? BigDecimal.ZERO : v; } private static BigDecimal scale2(BigDecimal v) { return v.setScale(2, java.math.RoundingMode.HALF_UP); } private static LocalDateTime nowUtc() { return LocalDateTime.now(java.time.Clock.systemUTC()); } @@ -364,10 +510,11 @@ public class OrderService { } private void ensureDefaultAccounts(Long shopId, Long userId) { - // 为 cash/bank/wechat 分别确保存在一条账户记录;按 type→name 顺序检查,避免同名唯一冲突 - ensureAccount(shopId, userId, "cash", "现金"); - ensureAccount(shopId, userId, "bank", "银行存款"); - ensureAccount(shopId, userId, "wechat", "微信"); + // 为 cash/bank/wechat/alipay 分别确保存在一条账户记录;按 type→name 顺序检查,避免同名唯一冲突 + ensureAccount(shopId, userId, "cash", accountDefaults.getCashName()); + ensureAccount(shopId, userId, "bank", accountDefaults.getBankName()); + ensureAccount(shopId, userId, "wechat", accountDefaults.getWechatName()); + ensureAccount(shopId, userId, "alipay", accountDefaults.getAlipayName()); } private void ensureAccount(Long shopId, Long userId, String type, String name) { @@ -383,8 +530,11 @@ public class OrderService { String type = "cash"; if ("bank".equalsIgnoreCase(method)) type = "bank"; if ("wechat".equalsIgnoreCase(method)) type = "wechat"; - String name = "现金"; - if ("bank".equals(type)) name = "银行存款"; else if ("wechat".equals(type)) name = "微信"; + if ("alipay".equalsIgnoreCase(method)) type = "alipay"; + String name = accountDefaults.getCashName(); + if ("bank".equals(type)) name = accountDefaults.getBankName(); + else if ("wechat".equals(type)) name = accountDefaults.getWechatName(); + else if ("alipay".equals(type)) name = accountDefaults.getAlipayName(); // 先按 type 查 List byType = jdbcTemplate.query("SELECT id FROM accounts WHERE shop_id=? AND type=? LIMIT 1", (rs,rn)->rs.getLong(1), shopId, type); if (!byType.isEmpty()) return byType.get(0); diff --git a/backend/src/main/java/com/example/demo/order/dto/OrderDtos.java b/backend/src/main/java/com/example/demo/order/dto/OrderDtos.java index 7ab2904..056ff49 100644 --- a/backend/src/main/java/com/example/demo/order/dto/OrderDtos.java +++ b/backend/src/main/java/com/example/demo/order/dto/OrderDtos.java @@ -39,6 +39,17 @@ public class OrderDtos { public java.util.List paymentIds; public CreatePaymentsResponse(java.util.List ids) { this.paymentIds = ids; } } + + public static class CreateOtherTransactionRequest { + public String type; // income | expense + public String category; // 分类key + public String counterpartyType; // customer | supplier | other + public Long counterpartyId; // 可空 + public Long accountId; // 必填 + public java.math.BigDecimal amount; // 必填,>0 + public String txTime; // yyyy-MM-dd 或 ISO8601 + public String remark; // 可空 + } } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 1745848..cfc98fc 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -4,7 +4,7 @@ spring.application.name=demo # 正确的配置 # 格式为: jdbc:mysql://<主机名>:<端口号>/<数据库名>?参数 # 默认附带 MySQL 8 推荐参数,避免握手/时区/编码问题 -spring.datasource.url=${DB_URL:jdbc:mysql://mysql.tonaspace.com:3306/partsinquiry?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8} +spring.datasource.url=${DB_URL:jdbc:mysql://mysql.tonaspace.com:3306/partsinquiry?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8mb4&connectionCollation=utf8mb4_0900_ai_ci} # 用户名和密码直接写值 spring.datasource.username=${DB_USER:root} @@ -16,6 +16,10 @@ spring.jpa.open-in-view=false spring.jpa.show-sql=false spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect +# 日志级别(开发调试) +logging.level.com.example.demo=DEBUG +logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=INFO + # CORS 简单放开(如需跨域) spring.web.cors.allowed-origins=${CORS_ALLOWED_ORIGINS:*} spring.web.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS @@ -38,3 +42,13 @@ attachments.placeholder.url-path=${ATTACHMENTS_PLACEHOLDER_URL:/api/attachments/ # 应用默认上下文(用于开发/演示环境) app.defaults.shop-id=${APP_DEFAULT_SHOP_ID:1} app.defaults.user-id=${APP_DEFAULT_USER_ID:2} + +# 财务分类默认配置(前端请调用 /api/finance/categories 获取,禁止硬编码) +app.finance.income-categories=${APP_FINANCE_INCOME:operation_income:经营所得,interest_income:利息收入,other_income:其它收入,deposit_ar_income:收订金/欠款,investment_income:投资收入,sale_income:销售收入,account_operation:账户操作,fund_transfer_in:资金转账转入} +app.finance.expense-categories=${APP_FINANCE_EXPENSE:operation_expense:经营支出,office_supplies:办公用品,rent:房租,interest_expense:利息支出,other_expense:其它支出,account_operation:账户操作,fund_transfer_out:资金转账转出} + +# 账户默认名称(避免硬编码,可被环境变量覆盖) +app.account.defaults.cash-name=${APP_ACCOUNT_CASH_NAME:现金} +app.account.defaults.bank-name=${APP_ACCOUNT_BANK_NAME:银行存款} +app.account.defaults.wechat-name=${APP_ACCOUNT_WECHAT_NAME:微信} +app.account.defaults.alipay-name=${APP_ACCOUNT_ALIPAY_NAME:支付宝} diff --git a/doc/database_documentation.md b/doc/database_documentation.md index 1bca6cc..ef1bedf 100644 --- a/doc/database_documentation.md +++ b/doc/database_documentation.md @@ -264,6 +264,8 @@ | user_id | BIGINT UNSIGNED | NOT NULL | | | | name | VARCHAR(64) | NOT NULL | | | | type | ENUM('cash','bank','alipay','wechat','other') | NOT NULL | cash | | +| bank_name | VARCHAR(64) | YES | | 银行名称(type=bank 可用) | +| bank_account | VARCHAR(64) | YES | | 银行账号(type=bank 可用) | | balance | DECIMAL(18,2) | NOT NULL | 0.00 | | | status | TINYINT UNSIGNED | NOT NULL | 1 | | | created_at | TIMESTAMP | NOT NULL | CURRENT_TIMESTAMP | | @@ -379,6 +381,22 @@ **Indexes**: - PRIMARY KEY: `id` - KEY: `idx_ot_shop_time` (`shop_id`,`tx_time`) - KEY: `idx_ot_account` (`account_id`) **Foreign Keys**: - `fk_ot_shop`: `shop_id` → `shops(id)` - `fk_ot_user`: `user_id` → `users(id)` - `fk_ot_account`: `account_id` → `accounts(id)` +### finance_categories +| Column Name | Data Type | Nullable | Default | Comment | +| ----------- | --------- | -------- | ------- | ------- | +| id | BIGINT UNSIGNED | NOT NULL | AUTO_INCREMENT | | +| shop_id | BIGINT UNSIGNED | NOT NULL | | | +| type | ENUM('income','expense') | NOT NULL | | 分类类型 | +| key | VARCHAR(64) | NOT NULL | | 分类键(稳定标识) | +| label | VARCHAR(64) | NOT NULL | | 分类名称(支持中文) | +| sort_order | INT | NOT NULL | 0 | 排序 | +| status | TINYINT UNSIGNED | NOT NULL | 1 | 1启用 0停用 | +| created_at | TIMESTAMP | NOT NULL | CURRENT_TIMESTAMP | | +| updated_at | TIMESTAMP | NOT NULL | CURRENT_TIMESTAMP | | + +**Indexes**: - PRIMARY KEY: `id` - UNIQUE: `ux_finance_cat` (`shop_id`,`type`,`key`) - KEY: `idx_finance_cat_shop_type` (`shop_id`,`type`) +**Foreign Keys**: - `fk_finance_cat_shop`: `shop_id` → `shops(id)` + ### 触发器 - `trg_products_bi`: BEFORE INSERT ON `products` → 设置 `products.search_text` - `trg_products_au`: BEFORE UPDATE ON `products` → 维护 `products.search_text` diff --git a/doc/openapi.yaml b/doc/openapi.yaml index c906c7f..26504a0 100644 --- a/doc/openapi.yaml +++ b/doc/openapi.yaml @@ -7,6 +7,38 @@ info: servers: - url: / paths: + /api/finance/categories: + get: + summary: 财务分类(✅ Fully Implemented) + description: 返回其他收入/支出的分类。读取顺序:finance_categories 表 → system_parameters → app.finance.* 默认配置;前端已接入开单页分类chips。 + parameters: + - in: header + name: X-Shop-Id + required: false + schema: { type: integer } + description: 店铺ID,缺省 1 + responses: + '200': + description: 成功 + content: + application/json: + schema: + type: object + properties: + incomeCategories: + type: array + items: + type: object + properties: + key: { type: string } + label: { type: string } + expenseCategories: + type: array + items: + type: object + properties: + key: { type: string } + label: { type: string } /api/dashboard/overview: get: summary: 首页概览(✅ Fully Implemented) @@ -65,7 +97,21 @@ paths: /api/accounts: get: summary: 账户列表(❌ Partially Implemented) - description: 前端账户选择页已接入,后端返回数组或 {list:[]} 皆可。 + description: 返回启用账户列表;支持数组或 {list:[]} 两种返回格式以兼容前端。 + parameters: + - in: query + name: kw + schema: { type: string } + - in: query + name: status + schema: { type: integer, enum: [0,1] } + description: 仅后台使用;前端默认不传即等同 status=1 + - in: query + name: page + schema: { type: integer, default: 1 } + - in: query + name: size + schema: { type: integer, default: 50 } responses: '200': description: 成功 @@ -82,6 +128,79 @@ paths: type: array items: $ref: '#/components/schemas/Account' + post: + summary: 新增账户(❌ Partially Implemented) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateAccountRequest' + responses: + '200': { description: 成功 } + /api/accounts/{id}: + put: + summary: 更新账户(❌ Partially Implemented) + parameters: + - in: path + name: id + required: true + schema: { type: integer, format: int64 } + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateAccountRequest' + responses: + '200': { description: 成功 } + /api/accounts/{id}/ledger: + get: + summary: 账户流水(❌ Partially Implemented) + parameters: + - in: path + name: id + required: true + schema: { type: integer, format: int64 } + - in: query + name: startDate + schema: { type: string, format: date } + - in: query + name: endDate + schema: { type: string, format: date } + - in: query + name: kw + schema: { type: string } + - in: query + name: page + schema: { type: integer, default: 1 } + - in: query + name: size + schema: { type: integer, default: 20 } + responses: + '200': + description: 成功 + content: + application/json: + schema: + type: object + properties: + opening: { type: number } + income: { type: number } + expense: { type: number } + ending: { type: number } + list: + type: array + items: + type: object + properties: + id: { type: integer, format: int64 } + txTime: { type: string, format: date-time } + direction: { type: string, enum: [in, out] } + amount: { type: number } + src: { type: string, description: 'payments/other' } + category: { type: string, nullable: true } + remark: { type: string, nullable: true } /api/suppliers: get: summary: 供应商搜索(✅ Fully Implemented) @@ -148,7 +267,7 @@ paths: '200': { description: 成功 } /api/other-transactions: post: - summary: 新建其他收入/支出(❌ Partially Implemented) + summary: 新建其他收入/支出(✅ Fully Implemented) requestBody: required: true content: @@ -448,8 +567,8 @@ paths: type: string /api/orders: get: - summary: 单据列表查询(❌ Partially Implemented) - description: 支持按时间范围与关键字筛选;参数 biz=sale|purchase,type=out|in|return;返回 {list:[]}。 + summary: 单据列表查询(✅ Fully Implemented) + description: 支持按时间范围与关键字筛选;参数 biz=sale|purchase,type=out|in|return;返回 {list:[]}。后端已返回驼峰字段与名称(sale: customerName;purchase: supplierName)。 parameters: - in: query name: biz @@ -500,7 +619,7 @@ paths: paymentIds: type: array items: { type: integer, format: int64 } - description: 支持按时间范围与关键字筛选;返回 {list:[]}。前端已接入,后端待实现。 + description: 收/付款创建。注意:根据约束,sale/purchase 收/付款必须绑定订单(orderId 不可为空)。 parameters: - in: query name: kw @@ -538,7 +657,7 @@ paths: /api/purchase-orders: get: - summary: 进货单列表查询(❌ Partially Implemented) + summary: 进货单列表查询(✅ Fully Implemented) parameters: - in: query name: kw @@ -581,7 +700,7 @@ paths: /api/payments: get: - summary: 收付款流水列表(❌ Partially Implemented) + summary: 收付款流水列表(✅ Fully Implemented) parameters: - in: query name: kw @@ -606,6 +725,7 @@ paths: schema: type: object properties: + totalAmount: { type: number } list: type: array items: @@ -614,13 +734,13 @@ paths: id: { type: integer, format: int64 } bizType: { type: string } direction: { type: string } - payTime: { type: string, format: date-time } + orderTime: { type: string, format: date-time, description: '支付时间,原 payTime' } amount: { type: number } accountName: { type: string } /api/inventories/logs: get: - summary: 库存/盘点流水列表(❌ Partially Implemented) + summary: 库存/盘点流水列表(✅ Fully Implemented) parameters: - in: query name: kw @@ -651,19 +771,116 @@ paths: schema: type: object properties: + totalAmount: { type: number } list: type: array items: type: object properties: id: { type: integer, format: int64 } - bizType: { type: string } txTime: { type: string, format: date-time } - amount: { type: number } + amount: { type: number, description: '金额变化(若无则0)' } remark: { type: string } productId: { type: integer, format: int64 } qtyDelta: { type: number } amountDelta: { type: number, nullable: true } + + /api/orders/{id}: + get: + summary: 销售单详情(✅ Fully Implemented) + parameters: + - in: path + name: id + required: true + schema: { type: integer, format: int64 } + responses: + '200': + description: 成功 + content: + application/json: + schema: + type: object + properties: + id: { type: integer, format: int64 } + orderNo: { type: string } + orderTime: { type: string, format: date-time } + status: { type: string } + amount: { type: number } + paidAmount: { type: number } + customerId: { type: integer, format: int64, nullable: true } + customerName: { type: string, nullable: true } + remark: { type: string, nullable: true } + items: + type: array + items: + type: object + properties: + productId: { type: integer, format: int64 } + name: { type: string } + spec: { type: string } + quantity: { type: number } + unitPrice: { type: number } + discountRate: { type: number } + amount: { type: number } + payments: + type: array + items: + type: object + properties: + id: { type: integer, format: int64 } + amount: { type: number } + payTime: { type: string, format: date-time } + accountId: { type: integer, format: int64 } + accountName: { type: string } + direction: { type: string } + + /api/purchase-orders/{id}: + get: + summary: 进货单详情(✅ Fully Implemented) + parameters: + - in: path + name: id + required: true + schema: { type: integer, format: int64 } + responses: + '200': + description: 成功 + content: + application/json: + schema: + type: object + properties: + id: { type: integer, format: int64 } + orderNo: { type: string } + orderTime: { type: string, format: date-time } + status: { type: string } + amount: { type: number } + paidAmount: { type: number } + supplierId: { type: integer, format: int64, nullable: true } + supplierName: { type: string, nullable: true } + remark: { type: string, nullable: true } + items: + type: array + items: + type: object + properties: + productId: { type: integer, format: int64 } + name: { type: string } + spec: { type: string } + quantity: { type: number } + unitPrice: { type: number } + amount: { type: number } + payments: + type: array + items: + type: object + properties: + id: { type: integer, format: int64 } + amount: { type: number } + payTime: { type: string, format: date-time } + accountId: { type: integer, format: int64 } + accountName: { type: string } + direction: { type: string } /api/attachments: post: summary: 上传附件(✅ Fully Implemented,占位图方案) @@ -772,6 +989,21 @@ components: enum: [cash, bank, alipay, wechat, other] balance: type: number + bankName: + type: string + nullable: true + bankAccount: + type: string + nullable: true + CreateAccountRequest: + type: object + properties: + name: { type: string } + type: { type: string, enum: [cash, bank, alipay, wechat, other] } + bankName: { type: string, nullable: true } + bankAccount: { type: string, nullable: true } + openingBalance: { type: number, nullable: true } + status: { type: integer, enum: [0,1], default: 1 } Supplier: type: object properties: @@ -803,6 +1035,9 @@ components: enum: [income, expense] category: type: string + counterpartyType: + type: string + enum: [customer, supplier, other] counterpartyId: type: integer format: int64 diff --git a/frontend/pages.json b/frontend/pages.json index 4b8de97..c111689 100644 --- a/frontend/pages.json +++ b/frontend/pages.json @@ -84,11 +84,47 @@ "navigationBarTitleText": "选择账户" } }, + { + "path": "pages/account/ledger", + "style": { + "navigationBarTitleText": "账户流水" + } + }, + { + "path": "pages/account/form", + "style": { + "navigationBarTitleText": "新增/编辑账户" + } + }, { "path": "pages/detail/index", "style": { "navigationBarTitleText": "明细" } + }, + { + "path": "pages/my/index", + "style": { + "navigationBarTitleText": "我的" + } + }, + { + "path": "pages/my/about", + "style": { + "navigationBarTitleText": "关于与协议" + } + }, + { + "path": "pages/report/index", + "style": { + "navigationBarTitleText": "报表" + } + }, + { + "path": "pages/report/entry", + "style": { + "navigationBarTitleText": "报表" + } } ], "globalStyle": { diff --git a/frontend/pages/account/form.vue b/frontend/pages/account/form.vue new file mode 100644 index 0000000..ff50443 --- /dev/null +++ b/frontend/pages/account/form.vue @@ -0,0 +1,74 @@ + + + + + + + diff --git a/frontend/pages/account/ledger.vue b/frontend/pages/account/ledger.vue new file mode 100644 index 0000000..8ea461f --- /dev/null +++ b/frontend/pages/account/ledger.vue @@ -0,0 +1,87 @@ + + + + + + + diff --git a/frontend/pages/account/select.vue b/frontend/pages/account/select.vue index 8271fec..d7363e8 100644 --- a/frontend/pages/account/select.vue +++ b/frontend/pages/account/select.vue @@ -6,6 +6,7 @@ {{ typeLabel(a.type) }} · 余额:{{ a.balance?.toFixed ? a.balance.toFixed(2) : a.balance }} + @@ -13,8 +14,9 @@ import { get } from '../../common/http.js' const TYPE_MAP = { cash: '现金', bank: '银行', alipay: '支付宝', wechat: '微信', other: '其他' } export default { - data() { return { accounts: [] } }, - async onLoad() { + data() { return { accounts: [], mode: 'view' } }, + async onLoad(q) { + this.mode = (q && q.mode) || 'view' try { const res = await get('/api/accounts') this.accounts = Array.isArray(res) ? res : (res?.list || []) @@ -22,13 +24,18 @@ }, methods: { select(a) { - const opener = getCurrentPages()[getCurrentPages().length-2] - if (opener && opener.$vm) { - opener.$vm.selectedAccountId = a.id - opener.$vm.selectedAccountName = a.name + if (this.mode === 'pick') { + const opener = getCurrentPages()[getCurrentPages().length-2] + if (opener && opener.$vm) { + opener.$vm.selectedAccountId = a.id + opener.$vm.selectedAccountName = a.name + } + uni.navigateBack() + } else { + uni.navigateTo({ url: `/pages/account/ledger?id=${a.id}` }) } - uni.navigateBack() }, + create() { uni.navigateTo({ url: '/pages/account/form' }) }, typeLabel(t) { return TYPE_MAP[t] || t } } } @@ -40,6 +47,7 @@ .item { padding: 20rpx 24rpx; background:#fff; border-bottom: 1rpx solid #f1f1f1; } .name { color:#333; margin-bottom: 6rpx; } .meta { color:#888; font-size: 24rpx; } + .fab { position: fixed; right: 32rpx; bottom: 120rpx; width: 100rpx; height: 100rpx; border-radius: 50%; background:#3c9cff; color:#fff; display:flex; align-items:center; justify-content:center; font-size: 52rpx; box-shadow: 0 10rpx 20rpx rgba(0,0,0,0.18); } diff --git a/frontend/pages/index/index.vue b/frontend/pages/index/index.vue index 42177b6..01284ce 100644 --- a/frontend/pages/index/index.vue +++ b/frontend/pages/index/index.vue @@ -78,10 +78,10 @@ 明细 - + 报表 - + 我的 @@ -156,6 +156,11 @@ uni.navigateTo({ url: '/pages/customer/select' }) return } + if (item.key === 'account') { + // 进入账户模块(先使用账户选择页,已对接后端 /api/accounts) + uni.navigateTo({ url: '/pages/account/select' }) + return + } if (item.key === 'supplier') { uni.navigateTo({ url: '/pages/supplier/select' }) return @@ -174,6 +179,14 @@ try { console.log('[index] goDetail → /pages/detail/index') } catch(e){} uni.navigateTo({ url: '/pages/detail/index' }) }, + goReport() { + this.activeTab = 'report' + uni.navigateTo({ url: '/pages/report/entry' }) + }, + goMe() { + this.activeTab = 'me' + uni.navigateTo({ url: '/pages/my/index' }) + }, onNoticeTap(n) { uni.showModal({ title: '广告', diff --git a/frontend/pages/my/about.vue b/frontend/pages/my/about.vue new file mode 100644 index 0000000..067c854 --- /dev/null +++ b/frontend/pages/my/about.vue @@ -0,0 +1,59 @@ + + + + + + + diff --git a/frontend/pages/my/index.vue b/frontend/pages/my/index.vue new file mode 100644 index 0000000..9695cb1 --- /dev/null +++ b/frontend/pages/my/index.vue @@ -0,0 +1,152 @@ + + + + + + + diff --git a/frontend/pages/order/create.vue b/frontend/pages/order/create.vue index 556e809..9312576 100644 --- a/frontend/pages/order/create.vue +++ b/frontend/pages/order/create.vue @@ -89,6 +89,11 @@ + + + + + {{ c.label }} @@ -139,8 +144,8 @@ + + + + diff --git a/frontend/pages/report/index.vue b/frontend/pages/report/index.vue new file mode 100644 index 0000000..dac1da5 --- /dev/null +++ b/frontend/pages/report/index.vue @@ -0,0 +1,291 @@ + + + + + + + diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/app.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/app.js.map index ac55a0c..9aa7a00 100644 --- a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/app.js.map +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/app.js.map @@ -1 +1 @@ -{"version":3,"file":"app.js","sources":["App.vue","main.js"],"sourcesContent":["\r\n\r\n\r\n","import App from './App'\r\n\r\n// #ifndef VUE3\r\nimport Vue from 'vue'\r\nimport './uni.promisify.adaptor'\r\nVue.config.productionTip = false\r\nApp.mpType = 'app'\r\nconst app = new Vue({\r\n ...App\r\n})\r\napp.$mount()\r\n// #endif\r\n\r\n// #ifdef VUE3\r\nimport { createSSRApp } from 'vue'\r\nexport function createApp() {\r\n const app = createSSRApp(App)\r\n return {\r\n app\r\n }\r\n}\r\n// #endif\r\n\r\n// 规范化 WebSocket 关闭码(仅微信小程序)\r\n// #ifdef MP-WEIXIN\r\nif (typeof uni !== 'undefined' && typeof uni.connectSocket === 'function') {\r\n const _connectSocket = uni.connectSocket\r\n uni.connectSocket = function(options) {\r\n const task = _connectSocket.call(this, options)\r\n if (task && typeof task.close === 'function') {\r\n const _close = task.close\r\n task.close = function(params = {}) {\r\n if (params && typeof params === 'object') {\r\n const codeNum = Number(params.code)\r\n const isValid = codeNum === 1000 || (codeNum >= 3000 && codeNum <= 4999)\r\n if (!isValid) {\r\n params.code = 1000\r\n if (!params.reason) params.reason = 'normalized from invalid close code'\r\n }\r\n }\r\n return _close.call(this, params)\r\n }\r\n }\r\n return task\r\n }\r\n}\r\n// #endif"],"names":["uni","createSSRApp","App"],"mappings":";;;;;;;;;;;;;;;;;;;;AACC,MAAK,YAAU;AAAA,EACd,UAAU,WAAW;AACpBA,kBAAAA,MAAA,MAAA,OAAA,gBAAY,YAAY;AAAA,EACxB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,gBAAA,UAAU;AAAA,EACtB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,iBAAA,UAAU;AAAA,EACvB;AACD;ACIM,SAAS,YAAY;AAC1B,QAAM,MAAMC,cAAY,aAACC,SAAG;AAC5B,SAAO;AAAA,IACL;AAAA,EACD;AACH;AAKA,IAAI,OAAOF,cAAG,UAAK,eAAe,OAAOA,cAAAA,MAAI,kBAAkB,YAAY;AACzE,QAAM,iBAAiBA,cAAAA,MAAI;AAC3BA,sBAAI,gBAAgB,SAAS,SAAS;AACpC,UAAM,OAAO,eAAe,KAAK,MAAM,OAAO;AAC9C,QAAI,QAAQ,OAAO,KAAK,UAAU,YAAY;AAC5C,YAAM,SAAS,KAAK;AACpB,WAAK,QAAQ,SAAS,SAAS,IAAI;AACjC,YAAI,UAAU,OAAO,WAAW,UAAU;AACxC,gBAAM,UAAU,OAAO,OAAO,IAAI;AAClC,gBAAM,UAAU,YAAY,OAAS,WAAW,OAAQ,WAAW;AACnE,cAAI,CAAC,SAAS;AACZ,mBAAO,OAAO;AACd,gBAAI,CAAC,OAAO;AAAQ,qBAAO,SAAS;AAAA,UACrC;AAAA,QACF;AACD,eAAO,OAAO,KAAK,MAAM,MAAM;AAAA,MAChC;AAAA,IACF;AACD,WAAO;AAAA,EACR;AACH;;;"} \ No newline at end of file +{"version":3,"file":"app.js","sources":["App.vue","main.js"],"sourcesContent":["\r\n\r\n\r\n","import App from './App'\r\n\r\n// #ifndef VUE3\r\nimport Vue from 'vue'\r\nimport './uni.promisify.adaptor'\r\nVue.config.productionTip = false\r\nApp.mpType = 'app'\r\nconst app = new Vue({\r\n ...App\r\n})\r\napp.$mount()\r\n// #endif\r\n\r\n// #ifdef VUE3\r\nimport { createSSRApp } from 'vue'\r\nexport function createApp() {\r\n const app = createSSRApp(App)\r\n return {\r\n app\r\n }\r\n}\r\n// #endif\r\n\r\n// 规范化 WebSocket 关闭码(仅微信小程序)\r\n// #ifdef MP-WEIXIN\r\nif (typeof uni !== 'undefined' && typeof uni.connectSocket === 'function') {\r\n const _connectSocket = uni.connectSocket\r\n uni.connectSocket = function(options) {\r\n const task = _connectSocket.call(this, options)\r\n if (task && typeof task.close === 'function') {\r\n const _close = task.close\r\n task.close = function(params = {}) {\r\n if (params && typeof params === 'object') {\r\n const codeNum = Number(params.code)\r\n const isValid = codeNum === 1000 || (codeNum >= 3000 && codeNum <= 4999)\r\n if (!isValid) {\r\n params.code = 1000\r\n if (!params.reason) params.reason = 'normalized from invalid close code'\r\n }\r\n }\r\n return _close.call(this, params)\r\n }\r\n }\r\n return task\r\n }\r\n}\r\n// #endif"],"names":["uni","createSSRApp","App"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACC,MAAK,YAAU;AAAA,EACd,UAAU,WAAW;AACpBA,kBAAAA,MAAA,MAAA,OAAA,gBAAY,YAAY;AAAA,EACxB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,gBAAA,UAAU;AAAA,EACtB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,iBAAA,UAAU;AAAA,EACvB;AACD;ACIM,SAAS,YAAY;AAC1B,QAAM,MAAMC,cAAY,aAACC,SAAG;AAC5B,SAAO;AAAA,IACL;AAAA,EACD;AACH;AAKA,IAAI,OAAOF,cAAG,UAAK,eAAe,OAAOA,cAAAA,MAAI,kBAAkB,YAAY;AACzE,QAAM,iBAAiBA,cAAAA,MAAI;AAC3BA,sBAAI,gBAAgB,SAAS,SAAS;AACpC,UAAM,OAAO,eAAe,KAAK,MAAM,OAAO;AAC9C,QAAI,QAAQ,OAAO,KAAK,UAAU,YAAY;AAC5C,YAAM,SAAS,KAAK;AACpB,WAAK,QAAQ,SAAS,SAAS,IAAI;AACjC,YAAI,UAAU,OAAO,WAAW,UAAU;AACxC,gBAAM,UAAU,OAAO,OAAO,IAAI;AAClC,gBAAM,UAAU,YAAY,OAAS,WAAW,OAAQ,WAAW;AACnE,cAAI,CAAC,SAAS;AACZ,mBAAO,OAAO;AACd,gBAAI,CAAC,OAAO;AAAQ,qBAAO,SAAS;AAAA,UACrC;AAAA,QACF;AACD,eAAO,OAAO,KAAK,MAAM,MAAM;AAAA,MAChC;AAAA,IACF;AACD,WAAO;AAAA,EACR;AACH;;;"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map index c4ca023..3cbf629 100644 --- a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/common/vendor.js.map @@ -1 +1 @@ -{"version":3,"file":"vendor.js","sources":["../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/node_modules/@vue/shared/dist/shared.esm-bundler.js","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-i18n/dist/uni-i18n.es.js","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-shared/dist/uni-shared.es.js","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-mp-vue/dist/vue.runtime.esm.js","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-mp-weixin/dist/uni.api.esm.js","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-console/dist/mp.esm.js","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-mp-weixin/dist/uni.mp.esm.js"],"sourcesContent":["/**\n* @vue/shared v3.4.21\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\nfunction makeMap(str, expectsLowerCase) {\n const set = new Set(str.split(\",\"));\n return expectsLowerCase ? (val) => set.has(val.toLowerCase()) : (val) => set.has(val);\n}\n\nconst EMPTY_OBJ = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze({}) : {};\nconst EMPTY_ARR = !!(process.env.NODE_ENV !== \"production\") ? Object.freeze([]) : [];\nconst NOOP = () => {\n};\nconst NO = () => false;\nconst isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && // uppercase letter\n(key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97);\nconst isModelListener = (key) => key.startsWith(\"onUpdate:\");\nconst extend = Object.assign;\nconst remove = (arr, el) => {\n const i = arr.indexOf(el);\n if (i > -1) {\n arr.splice(i, 1);\n }\n};\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst hasOwn = (val, key) => hasOwnProperty.call(val, key);\nconst isArray = Array.isArray;\nconst isMap = (val) => toTypeString(val) === \"[object Map]\";\nconst isSet = (val) => toTypeString(val) === \"[object Set]\";\nconst isDate = (val) => toTypeString(val) === \"[object Date]\";\nconst isRegExp = (val) => toTypeString(val) === \"[object RegExp]\";\nconst isFunction = (val) => typeof val === \"function\";\nconst isString = (val) => typeof val === \"string\";\nconst isSymbol = (val) => typeof val === \"symbol\";\nconst isObject = (val) => val !== null && typeof val === \"object\";\nconst isPromise = (val) => {\n return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch);\n};\nconst objectToString = Object.prototype.toString;\nconst toTypeString = (value) => objectToString.call(value);\nconst toRawType = (value) => {\n return toTypeString(value).slice(8, -1);\n};\nconst isPlainObject = (val) => toTypeString(val) === \"[object Object]\";\nconst isIntegerKey = (key) => isString(key) && key !== \"NaN\" && key[0] !== \"-\" && \"\" + parseInt(key, 10) === key;\nconst isReservedProp = /* @__PURE__ */ makeMap(\n // the leading comma is intentional so empty string \"\" is also included\n \",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted\"\n);\nconst isBuiltInDirective = /* @__PURE__ */ makeMap(\n \"bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo\"\n);\nconst cacheStringFunction = (fn) => {\n const cache = /* @__PURE__ */ Object.create(null);\n return (str) => {\n const hit = cache[str];\n return hit || (cache[str] = fn(str));\n };\n};\nconst camelizeRE = /-(\\w)/g;\nconst camelize = cacheStringFunction((str) => {\n return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : \"\");\n});\nconst hyphenateRE = /\\B([A-Z])/g;\nconst hyphenate = cacheStringFunction(\n (str) => str.replace(hyphenateRE, \"-$1\").toLowerCase()\n);\nconst capitalize = cacheStringFunction((str) => {\n return str.charAt(0).toUpperCase() + str.slice(1);\n});\nconst toHandlerKey = cacheStringFunction((str) => {\n const s = str ? `on${capitalize(str)}` : ``;\n return s;\n});\nconst hasChanged = (value, oldValue) => !Object.is(value, oldValue);\nconst invokeArrayFns = (fns, arg) => {\n for (let i = 0; i < fns.length; i++) {\n fns[i](arg);\n }\n};\nconst def = (obj, key, value) => {\n Object.defineProperty(obj, key, {\n configurable: true,\n enumerable: false,\n value\n });\n};\nconst looseToNumber = (val) => {\n const n = parseFloat(val);\n return isNaN(n) ? val : n;\n};\nconst toNumber = (val) => {\n const n = isString(val) ? Number(val) : NaN;\n return isNaN(n) ? val : n;\n};\nlet _globalThis;\nconst getGlobalThis = () => {\n return _globalThis || (_globalThis = typeof globalThis !== \"undefined\" ? globalThis : typeof self !== \"undefined\" ? self : typeof window !== \"undefined\" ? window : typeof global !== \"undefined\" ? global : {});\n};\nconst identRE = /^[_$a-zA-Z\\xA0-\\uFFFF][_$a-zA-Z0-9\\xA0-\\uFFFF]*$/;\nfunction genPropsAccessExp(name) {\n return identRE.test(name) ? `__props.${name}` : `__props[${JSON.stringify(name)}]`;\n}\n\nconst PatchFlags = {\n \"TEXT\": 1,\n \"1\": \"TEXT\",\n \"CLASS\": 2,\n \"2\": \"CLASS\",\n \"STYLE\": 4,\n \"4\": \"STYLE\",\n \"PROPS\": 8,\n \"8\": \"PROPS\",\n \"FULL_PROPS\": 16,\n \"16\": \"FULL_PROPS\",\n \"NEED_HYDRATION\": 32,\n \"32\": \"NEED_HYDRATION\",\n \"STABLE_FRAGMENT\": 64,\n \"64\": \"STABLE_FRAGMENT\",\n \"KEYED_FRAGMENT\": 128,\n \"128\": \"KEYED_FRAGMENT\",\n \"UNKEYED_FRAGMENT\": 256,\n \"256\": \"UNKEYED_FRAGMENT\",\n \"NEED_PATCH\": 512,\n \"512\": \"NEED_PATCH\",\n \"DYNAMIC_SLOTS\": 1024,\n \"1024\": \"DYNAMIC_SLOTS\",\n \"DEV_ROOT_FRAGMENT\": 2048,\n \"2048\": \"DEV_ROOT_FRAGMENT\",\n \"HOISTED\": -1,\n \"-1\": \"HOISTED\",\n \"BAIL\": -2,\n \"-2\": \"BAIL\"\n};\nconst PatchFlagNames = {\n [1]: `TEXT`,\n [2]: `CLASS`,\n [4]: `STYLE`,\n [8]: `PROPS`,\n [16]: `FULL_PROPS`,\n [32]: `NEED_HYDRATION`,\n [64]: `STABLE_FRAGMENT`,\n [128]: `KEYED_FRAGMENT`,\n [256]: `UNKEYED_FRAGMENT`,\n [512]: `NEED_PATCH`,\n [1024]: `DYNAMIC_SLOTS`,\n [2048]: `DEV_ROOT_FRAGMENT`,\n [-1]: `HOISTED`,\n [-2]: `BAIL`\n};\n\nconst ShapeFlags = {\n \"ELEMENT\": 1,\n \"1\": \"ELEMENT\",\n \"FUNCTIONAL_COMPONENT\": 2,\n \"2\": \"FUNCTIONAL_COMPONENT\",\n \"STATEFUL_COMPONENT\": 4,\n \"4\": \"STATEFUL_COMPONENT\",\n \"TEXT_CHILDREN\": 8,\n \"8\": \"TEXT_CHILDREN\",\n \"ARRAY_CHILDREN\": 16,\n \"16\": \"ARRAY_CHILDREN\",\n \"SLOTS_CHILDREN\": 32,\n \"32\": \"SLOTS_CHILDREN\",\n \"TELEPORT\": 64,\n \"64\": \"TELEPORT\",\n \"SUSPENSE\": 128,\n \"128\": \"SUSPENSE\",\n \"COMPONENT_SHOULD_KEEP_ALIVE\": 256,\n \"256\": \"COMPONENT_SHOULD_KEEP_ALIVE\",\n \"COMPONENT_KEPT_ALIVE\": 512,\n \"512\": \"COMPONENT_KEPT_ALIVE\",\n \"COMPONENT\": 6,\n \"6\": \"COMPONENT\"\n};\n\nconst SlotFlags = {\n \"STABLE\": 1,\n \"1\": \"STABLE\",\n \"DYNAMIC\": 2,\n \"2\": \"DYNAMIC\",\n \"FORWARDED\": 3,\n \"3\": \"FORWARDED\"\n};\nconst slotFlagsText = {\n [1]: \"STABLE\",\n [2]: \"DYNAMIC\",\n [3]: \"FORWARDED\"\n};\n\nconst GLOBALS_ALLOWED = \"Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error\";\nconst isGloballyAllowed = /* @__PURE__ */ makeMap(GLOBALS_ALLOWED);\nconst isGloballyWhitelisted = isGloballyAllowed;\n\nconst range = 2;\nfunction generateCodeFrame(source, start = 0, end = source.length) {\n let lines = source.split(/(\\r?\\n)/);\n const newlineSequences = lines.filter((_, idx) => idx % 2 === 1);\n lines = lines.filter((_, idx) => idx % 2 === 0);\n let count = 0;\n const res = [];\n for (let i = 0; i < lines.length; i++) {\n count += lines[i].length + (newlineSequences[i] && newlineSequences[i].length || 0);\n if (count >= start) {\n for (let j = i - range; j <= i + range || end > count; j++) {\n if (j < 0 || j >= lines.length)\n continue;\n const line = j + 1;\n res.push(\n `${line}${\" \".repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}`\n );\n const lineLength = lines[j].length;\n const newLineSeqLength = newlineSequences[j] && newlineSequences[j].length || 0;\n if (j === i) {\n const pad = start - (count - (lineLength + newLineSeqLength));\n const length = Math.max(\n 1,\n end > count ? lineLength - pad : end - start\n );\n res.push(` | ` + \" \".repeat(pad) + \"^\".repeat(length));\n } else if (j > i) {\n if (end > count) {\n const length = Math.max(Math.min(end - count, lineLength), 1);\n res.push(` | ` + \"^\".repeat(length));\n }\n count += lineLength + newLineSeqLength;\n }\n }\n break;\n }\n }\n return res.join(\"\\n\");\n}\n\nfunction normalizeStyle(value) {\n if (isArray(value)) {\n const res = {};\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item);\n if (normalized) {\n for (const key in normalized) {\n res[key] = normalized[key];\n }\n }\n }\n return res;\n } else if (isString(value) || isObject(value)) {\n return value;\n }\n}\nconst listDelimiterRE = /;(?![^(]*\\))/g;\nconst propertyDelimiterRE = /:([^]+)/;\nconst styleCommentRE = /\\/\\*[^]*?\\*\\//g;\nfunction parseStringStyle(cssText) {\n const ret = {};\n cssText.replace(styleCommentRE, \"\").split(listDelimiterRE).forEach((item) => {\n if (item) {\n const tmp = item.split(propertyDelimiterRE);\n tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim());\n }\n });\n return ret;\n}\nfunction stringifyStyle(styles) {\n let ret = \"\";\n if (!styles || isString(styles)) {\n return ret;\n }\n for (const key in styles) {\n const value = styles[key];\n const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key);\n if (isString(value) || typeof value === \"number\") {\n ret += `${normalizedKey}:${value};`;\n }\n }\n return ret;\n}\nfunction normalizeClass(value) {\n let res = \"\";\n if (isString(value)) {\n res = value;\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const normalized = normalizeClass(value[i]);\n if (normalized) {\n res += normalized + \" \";\n }\n }\n } else if (isObject(value)) {\n for (const name in value) {\n if (value[name]) {\n res += name + \" \";\n }\n }\n }\n return res.trim();\n}\nfunction normalizeProps(props) {\n if (!props)\n return null;\n let { class: klass, style } = props;\n if (klass && !isString(klass)) {\n props.class = normalizeClass(klass);\n }\n if (style) {\n props.style = normalizeStyle(style);\n }\n return props;\n}\n\nconst HTML_TAGS = \"html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot\";\nconst SVG_TAGS = \"svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view\";\nconst MATH_TAGS = \"annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics\";\nconst VOID_TAGS = \"area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr\";\nconst isHTMLTag = /* @__PURE__ */ makeMap(HTML_TAGS);\nconst isSVGTag = /* @__PURE__ */ makeMap(SVG_TAGS);\nconst isMathMLTag = /* @__PURE__ */ makeMap(MATH_TAGS);\nconst isVoidTag = /* @__PURE__ */ makeMap(VOID_TAGS);\n\nconst specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;\nconst isSpecialBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs);\nconst isBooleanAttr = /* @__PURE__ */ makeMap(\n specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected`\n);\nfunction includeBooleanAttr(value) {\n return !!value || value === \"\";\n}\nconst unsafeAttrCharRE = /[>/=\"'\\u0009\\u000a\\u000c\\u0020]/;\nconst attrValidationCache = {};\nfunction isSSRSafeAttrName(name) {\n if (attrValidationCache.hasOwnProperty(name)) {\n return attrValidationCache[name];\n }\n const isUnsafe = unsafeAttrCharRE.test(name);\n if (isUnsafe) {\n console.error(`unsafe attribute name: ${name}`);\n }\n return attrValidationCache[name] = !isUnsafe;\n}\nconst propsToAttrMap = {\n acceptCharset: \"accept-charset\",\n className: \"class\",\n htmlFor: \"for\",\n httpEquiv: \"http-equiv\"\n};\nconst isKnownHtmlAttr = /* @__PURE__ */ makeMap(\n `accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap`\n);\nconst isKnownSvgAttr = /* @__PURE__ */ makeMap(\n `xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,color-interpolation-filters,color-profile,color-rendering,contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,overflow,overline-position,overline-thickness,panose-1,paint-order,path,pathLength,patternContentUnits,patternTransform,patternUnits,ping,pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,specularConstant,specularExponent,speed,spreadMethod,startOffset,stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,string,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,text-decoration,text-rendering,textLength,to,transform,transform-origin,type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan`\n);\nfunction isRenderableAttrValue(value) {\n if (value == null) {\n return false;\n }\n const type = typeof value;\n return type === \"string\" || type === \"number\" || type === \"boolean\";\n}\n\nconst escapeRE = /[\"'&<>]/;\nfunction escapeHtml(string) {\n const str = \"\" + string;\n const match = escapeRE.exec(str);\n if (!match) {\n return str;\n }\n let html = \"\";\n let escaped;\n let index;\n let lastIndex = 0;\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34:\n escaped = \""\";\n break;\n case 38:\n escaped = \"&\";\n break;\n case 39:\n escaped = \"'\";\n break;\n case 60:\n escaped = \"<\";\n break;\n case 62:\n escaped = \">\";\n break;\n default:\n continue;\n }\n if (lastIndex !== index) {\n html += str.slice(lastIndex, index);\n }\n lastIndex = index + 1;\n html += escaped;\n }\n return lastIndex !== index ? html + str.slice(lastIndex, index) : html;\n}\nconst commentStripRE = /^-?>||--!>| looseEqual(item, val));\n}\n\nconst toDisplayString = (val) => {\n return isString(val) ? val : val == null ? \"\" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? JSON.stringify(val, replacer, 2) : String(val);\n};\nconst replacer = (_key, val) => {\n if (val && val.__v_isRef) {\n return replacer(_key, val.value);\n } else if (isMap(val)) {\n return {\n [`Map(${val.size})`]: [...val.entries()].reduce(\n (entries, [key, val2], i) => {\n entries[stringifySymbol(key, i) + \" =>\"] = val2;\n return entries;\n },\n {}\n )\n };\n } else if (isSet(val)) {\n return {\n [`Set(${val.size})`]: [...val.values()].map((v) => stringifySymbol(v))\n };\n } else if (isSymbol(val)) {\n return stringifySymbol(val);\n } else if (isObject(val) && !isArray(val) && !isPlainObject(val)) {\n return String(val);\n }\n return val;\n};\nconst stringifySymbol = (v, i = \"\") => {\n var _a;\n return isSymbol(v) ? `Symbol(${(_a = v.description) != null ? _a : i})` : v;\n};\n\nexport { EMPTY_ARR, EMPTY_OBJ, NO, NOOP, PatchFlagNames, PatchFlags, ShapeFlags, SlotFlags, camelize, capitalize, def, escapeHtml, escapeHtmlComment, extend, genPropsAccessExp, generateCodeFrame, getGlobalThis, hasChanged, hasOwn, hyphenate, includeBooleanAttr, invokeArrayFns, isArray, isBooleanAttr, isBuiltInDirective, isDate, isFunction, isGloballyAllowed, isGloballyWhitelisted, isHTMLTag, isIntegerKey, isKnownHtmlAttr, isKnownSvgAttr, isMap, isMathMLTag, isModelListener, isObject, isOn, isPlainObject, isPromise, isRegExp, isRenderableAttrValue, isReservedProp, isSSRSafeAttrName, isSVGTag, isSet, isSpecialBooleanAttr, isString, isSymbol, isVoidTag, looseEqual, looseIndexOf, looseToNumber, makeMap, normalizeClass, normalizeProps, normalizeStyle, objectToString, parseStringStyle, propsToAttrMap, remove, slotFlagsText, stringifyStyle, toDisplayString, toHandlerKey, toNumber, toRawType, toTypeString };\n","const isObject = (val) => val !== null && typeof val === 'object';\nconst defaultDelimiters = ['{', '}'];\nclass BaseFormatter {\n constructor() {\n this._caches = Object.create(null);\n }\n interpolate(message, values, delimiters = defaultDelimiters) {\n if (!values) {\n return [message];\n }\n let tokens = this._caches[message];\n if (!tokens) {\n tokens = parse(message, delimiters);\n this._caches[message] = tokens;\n }\n return compile(tokens, values);\n }\n}\nconst RE_TOKEN_LIST_VALUE = /^(?:\\d)+/;\nconst RE_TOKEN_NAMED_VALUE = /^(?:\\w)+/;\nfunction parse(format, [startDelimiter, endDelimiter]) {\n const tokens = [];\n let position = 0;\n let text = '';\n while (position < format.length) {\n let char = format[position++];\n if (char === startDelimiter) {\n if (text) {\n tokens.push({ type: 'text', value: text });\n }\n text = '';\n let sub = '';\n char = format[position++];\n while (char !== undefined && char !== endDelimiter) {\n sub += char;\n char = format[position++];\n }\n const isClosed = char === endDelimiter;\n const type = RE_TOKEN_LIST_VALUE.test(sub)\n ? 'list'\n : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)\n ? 'named'\n : 'unknown';\n tokens.push({ value: sub, type });\n }\n // else if (char === '%') {\n // // when found rails i18n syntax, skip text capture\n // if (format[position] !== '{') {\n // text += char\n // }\n // }\n else {\n text += char;\n }\n }\n text && tokens.push({ type: 'text', value: text });\n return tokens;\n}\nfunction compile(tokens, values) {\n const compiled = [];\n let index = 0;\n const mode = Array.isArray(values)\n ? 'list'\n : isObject(values)\n ? 'named'\n : 'unknown';\n if (mode === 'unknown') {\n return compiled;\n }\n while (index < tokens.length) {\n const token = tokens[index];\n switch (token.type) {\n case 'text':\n compiled.push(token.value);\n break;\n case 'list':\n compiled.push(values[parseInt(token.value, 10)]);\n break;\n case 'named':\n if (mode === 'named') {\n compiled.push(values[token.value]);\n }\n else {\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`);\n }\n }\n break;\n case 'unknown':\n if (process.env.NODE_ENV !== 'production') {\n console.warn(`Detect 'unknown' type of token!`);\n }\n break;\n }\n index++;\n }\n return compiled;\n}\n\nconst LOCALE_ZH_HANS = 'zh-Hans';\nconst LOCALE_ZH_HANT = 'zh-Hant';\nconst LOCALE_EN = 'en';\nconst LOCALE_FR = 'fr';\nconst LOCALE_ES = 'es';\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst hasOwn = (val, key) => hasOwnProperty.call(val, key);\nconst defaultFormatter = new BaseFormatter();\nfunction include(str, parts) {\n return !!parts.find((part) => str.indexOf(part) !== -1);\n}\nfunction startsWith(str, parts) {\n return parts.find((part) => str.indexOf(part) === 0);\n}\nfunction normalizeLocale(locale, messages) {\n if (!locale) {\n return;\n }\n locale = locale.trim().replace(/_/g, '-');\n if (messages && messages[locale]) {\n return locale;\n }\n locale = locale.toLowerCase();\n if (locale === 'chinese') {\n // 支付宝\n return LOCALE_ZH_HANS;\n }\n if (locale.indexOf('zh') === 0) {\n if (locale.indexOf('-hans') > -1) {\n return LOCALE_ZH_HANS;\n }\n if (locale.indexOf('-hant') > -1) {\n return LOCALE_ZH_HANT;\n }\n if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {\n return LOCALE_ZH_HANT;\n }\n return LOCALE_ZH_HANS;\n }\n let locales = [LOCALE_EN, LOCALE_FR, LOCALE_ES];\n if (messages && Object.keys(messages).length > 0) {\n locales = Object.keys(messages);\n }\n const lang = startsWith(locale, locales);\n if (lang) {\n return lang;\n }\n}\nclass I18n {\n constructor({ locale, fallbackLocale, messages, watcher, formater, }) {\n this.locale = LOCALE_EN;\n this.fallbackLocale = LOCALE_EN;\n this.message = {};\n this.messages = {};\n this.watchers = [];\n if (fallbackLocale) {\n this.fallbackLocale = fallbackLocale;\n }\n this.formater = formater || defaultFormatter;\n this.messages = messages || {};\n this.setLocale(locale || LOCALE_EN);\n if (watcher) {\n this.watchLocale(watcher);\n }\n }\n setLocale(locale) {\n const oldLocale = this.locale;\n this.locale = normalizeLocale(locale, this.messages) || this.fallbackLocale;\n if (!this.messages[this.locale]) {\n // 可能初始化时不存在\n this.messages[this.locale] = {};\n }\n this.message = this.messages[this.locale];\n // 仅发生变化时,通知\n if (oldLocale !== this.locale) {\n this.watchers.forEach((watcher) => {\n watcher(this.locale, oldLocale);\n });\n }\n }\n getLocale() {\n return this.locale;\n }\n watchLocale(fn) {\n const index = this.watchers.push(fn) - 1;\n return () => {\n this.watchers.splice(index, 1);\n };\n }\n add(locale, message, override = true) {\n const curMessages = this.messages[locale];\n if (curMessages) {\n if (override) {\n Object.assign(curMessages, message);\n }\n else {\n Object.keys(message).forEach((key) => {\n if (!hasOwn(curMessages, key)) {\n curMessages[key] = message[key];\n }\n });\n }\n }\n else {\n this.messages[locale] = message;\n }\n }\n f(message, values, delimiters) {\n return this.formater.interpolate(message, values, delimiters).join('');\n }\n t(key, locale, values) {\n let message = this.message;\n if (typeof locale === 'string') {\n locale = normalizeLocale(locale, this.messages);\n locale && (message = this.messages[locale]);\n }\n else {\n values = locale;\n }\n if (!hasOwn(message, key)) {\n console.warn(`Cannot translate the value of keypath ${key}. Use the value of keypath as default.`);\n return key;\n }\n return this.formater.interpolate(message[key], values).join('');\n }\n}\n\nfunction watchAppLocale(appVm, i18n) {\n // 需要保证 watch 的触发在组件渲染之前\n if (appVm.$watchLocale) {\n // vue2\n appVm.$watchLocale((newLocale) => {\n i18n.setLocale(newLocale);\n });\n }\n else {\n appVm.$watch(() => appVm.$locale, (newLocale) => {\n i18n.setLocale(newLocale);\n });\n }\n}\nfunction getDefaultLocale() {\n if (typeof uni !== 'undefined' && uni.getLocale) {\n return uni.getLocale();\n }\n // 小程序平台,uni 和 uni-i18n 互相引用,导致访问不到 uni,故在 global 上挂了 getLocale\n if (typeof global !== 'undefined' && global.getLocale) {\n return global.getLocale();\n }\n return LOCALE_EN;\n}\nfunction initVueI18n(locale, messages = {}, fallbackLocale, watcher) {\n // 兼容旧版本入参\n if (typeof locale !== 'string') {\n // ;[locale, messages] = [\n // messages as unknown as string,\n // locale as unknown as LocaleMessages,\n // ]\n // 暂不使用数组解构,uts编译器暂未支持。\n const options = [\n messages,\n locale,\n ];\n locale = options[0];\n messages = options[1];\n }\n if (typeof locale !== 'string') {\n // 因为小程序平台,uni-i18n 和 uni 互相引用,导致此时访问 uni 时,为 undefined\n locale = getDefaultLocale();\n }\n if (typeof fallbackLocale !== 'string') {\n fallbackLocale =\n (typeof __uniConfig !== 'undefined' && __uniConfig.fallbackLocale) ||\n LOCALE_EN;\n }\n const i18n = new I18n({\n locale,\n fallbackLocale,\n messages,\n watcher,\n });\n let t = (key, values) => {\n if (typeof getApp !== 'function') {\n // app view\n /* eslint-disable no-func-assign */\n t = function (key, values) {\n return i18n.t(key, values);\n };\n }\n else {\n let isWatchedAppLocale = false;\n t = function (key, values) {\n const appVm = getApp().$vm;\n // 可能$vm还不存在,比如在支付宝小程序中,组件定义较早,在props的default里使用了t()函数(如uni-goods-nav),此时app还未初始化\n // options: {\n // \ttype: Array,\n // \tdefault () {\n // \t\treturn [{\n // \t\t\ticon: 'shop',\n // \t\t\ttext: t(\"uni-goods-nav.options.shop\"),\n // \t\t}, {\n // \t\t\ticon: 'cart',\n // \t\t\ttext: t(\"uni-goods-nav.options.cart\")\n // \t\t}]\n // \t}\n // },\n if (appVm) {\n // 触发响应式\n appVm.$locale;\n if (!isWatchedAppLocale) {\n isWatchedAppLocale = true;\n watchAppLocale(appVm, i18n);\n }\n }\n return i18n.t(key, values);\n };\n }\n return t(key, values);\n };\n return {\n i18n,\n f(message, values, delimiters) {\n return i18n.f(message, values, delimiters);\n },\n t(key, values) {\n return t(key, values);\n },\n add(locale, message, override = true) {\n return i18n.add(locale, message, override);\n },\n watch(fn) {\n return i18n.watchLocale(fn);\n },\n getLocale() {\n return i18n.getLocale();\n },\n setLocale(newLocale) {\n return i18n.setLocale(newLocale);\n },\n };\n}\n\nconst isString = (val) => typeof val === 'string';\nlet formater;\nfunction hasI18nJson(jsonObj, delimiters) {\n if (!formater) {\n formater = new BaseFormatter();\n }\n return walkJsonObj(jsonObj, (jsonObj, key) => {\n const value = jsonObj[key];\n if (isString(value)) {\n if (isI18nStr(value, delimiters)) {\n return true;\n }\n }\n else {\n return hasI18nJson(value, delimiters);\n }\n });\n}\nfunction parseI18nJson(jsonObj, values, delimiters) {\n if (!formater) {\n formater = new BaseFormatter();\n }\n walkJsonObj(jsonObj, (jsonObj, key) => {\n const value = jsonObj[key];\n if (isString(value)) {\n if (isI18nStr(value, delimiters)) {\n jsonObj[key] = compileStr(value, values, delimiters);\n }\n }\n else {\n parseI18nJson(value, values, delimiters);\n }\n });\n return jsonObj;\n}\nfunction compileI18nJsonStr(jsonStr, { locale, locales, delimiters, }) {\n if (!isI18nStr(jsonStr, delimiters)) {\n return jsonStr;\n }\n if (!formater) {\n formater = new BaseFormatter();\n }\n const localeValues = [];\n Object.keys(locales).forEach((name) => {\n if (name !== locale) {\n localeValues.push({\n locale: name,\n values: locales[name],\n });\n }\n });\n localeValues.unshift({ locale, values: locales[locale] });\n try {\n return JSON.stringify(compileJsonObj(JSON.parse(jsonStr), localeValues, delimiters), null, 2);\n }\n catch (e) { }\n return jsonStr;\n}\nfunction isI18nStr(value, delimiters) {\n return value.indexOf(delimiters[0]) > -1;\n}\nfunction compileStr(value, values, delimiters) {\n return formater.interpolate(value, values, delimiters).join('');\n}\nfunction compileValue(jsonObj, key, localeValues, delimiters) {\n const value = jsonObj[key];\n if (isString(value)) {\n // 存在国际化\n if (isI18nStr(value, delimiters)) {\n jsonObj[key] = compileStr(value, localeValues[0].values, delimiters);\n if (localeValues.length > 1) {\n // 格式化国际化语言\n const valueLocales = (jsonObj[key + 'Locales'] = {});\n localeValues.forEach((localValue) => {\n valueLocales[localValue.locale] = compileStr(value, localValue.values, delimiters);\n });\n }\n }\n }\n else {\n compileJsonObj(value, localeValues, delimiters);\n }\n}\nfunction compileJsonObj(jsonObj, localeValues, delimiters) {\n walkJsonObj(jsonObj, (jsonObj, key) => {\n compileValue(jsonObj, key, localeValues, delimiters);\n });\n return jsonObj;\n}\nfunction walkJsonObj(jsonObj, walk) {\n if (Array.isArray(jsonObj)) {\n for (let i = 0; i < jsonObj.length; i++) {\n if (walk(jsonObj, i)) {\n return true;\n }\n }\n }\n else if (isObject(jsonObj)) {\n for (const key in jsonObj) {\n if (walk(jsonObj, key)) {\n return true;\n }\n }\n }\n return false;\n}\n\nfunction resolveLocale(locales) {\n return (locale) => {\n if (!locale) {\n return locale;\n }\n locale = normalizeLocale(locale) || locale;\n return resolveLocaleChain(locale).find((locale) => locales.indexOf(locale) > -1);\n };\n}\nfunction resolveLocaleChain(locale) {\n const chain = [];\n const tokens = locale.split('-');\n while (tokens.length) {\n chain.push(tokens.join('-'));\n tokens.pop();\n }\n return chain;\n}\n\nexport { BaseFormatter as Formatter, I18n, LOCALE_EN, LOCALE_ES, LOCALE_FR, LOCALE_ZH_HANS, LOCALE_ZH_HANT, compileI18nJsonStr, hasI18nJson, initVueI18n, isI18nStr, isString, normalizeLocale, parseI18nJson, resolveLocale };\n","import { isHTMLTag, isSVGTag, isVoidTag, isString, isFunction, isPlainObject, hyphenate, camelize, normalizeStyle as normalizeStyle$1, parseStringStyle, isArray, normalizeClass as normalizeClass$1, extend, capitalize, makeMap } from '@vue/shared';\n\nconst BUILT_IN_TAG_NAMES = [\n 'ad',\n 'ad-content-page',\n 'ad-draw',\n 'audio',\n 'button',\n 'camera',\n 'canvas',\n 'checkbox',\n 'checkbox-group',\n 'cover-image',\n 'cover-view',\n 'editor',\n 'form',\n 'functional-page-navigator',\n 'icon',\n 'image',\n 'input',\n 'label',\n 'live-player',\n 'live-pusher',\n 'map',\n 'movable-area',\n 'movable-view',\n 'navigator',\n 'official-account',\n 'open-data',\n 'picker',\n 'picker-view',\n 'picker-view-column',\n 'progress',\n 'radio',\n 'radio-group',\n 'rich-text',\n 'scroll-view',\n 'slider',\n 'swiper',\n 'swiper-item',\n 'switch',\n 'text',\n 'textarea',\n 'video',\n 'view',\n 'web-view',\n 'location-picker',\n 'location-view',\n];\nconst BUILT_IN_TAGS = BUILT_IN_TAG_NAMES.map((tag) => 'uni-' + tag);\nconst TAGS = [\n 'app',\n 'layout',\n 'content',\n 'main',\n 'top-window',\n 'left-window',\n 'right-window',\n 'tabbar',\n 'page',\n 'page-head',\n 'page-wrapper',\n 'page-body',\n 'page-refresh',\n 'actionsheet',\n 'modal',\n 'toast',\n 'resize-sensor',\n 'shadow-root',\n].map((tag) => 'uni-' + tag);\nconst NVUE_BUILT_IN_TAGS = [\n 'svg',\n 'view',\n 'a',\n 'div',\n 'img',\n 'image',\n 'text',\n 'span',\n 'input',\n 'textarea',\n 'spinner',\n 'select',\n // slider 被自定义 u-slider 替代\n // 'slider',\n 'slider-neighbor',\n 'indicator',\n 'canvas',\n 'list',\n 'cell',\n 'header',\n 'loading',\n 'loading-indicator',\n 'refresh',\n 'scrollable',\n 'scroller',\n 'video',\n 'web',\n 'embed',\n 'tabbar',\n 'tabheader',\n 'datepicker',\n 'timepicker',\n 'marquee',\n 'countdown',\n 'dc-switch',\n 'waterfall',\n 'richtext',\n 'recycle-list',\n 'u-scalable',\n 'barcode',\n 'gcanvas',\n];\nconst UVUE_BUILT_IN_TAGS = [\n 'ad',\n 'ad-content-page',\n 'ad-draw',\n 'native-view',\n 'loading-indicator',\n 'list-view',\n 'list-item',\n 'swiper',\n 'swiper-item',\n 'rich-text',\n 'sticky-view',\n 'sticky-header',\n 'sticky-section',\n // 自定义\n 'uni-slider',\n // 原生实现\n 'button',\n 'nested-scroll-header',\n 'nested-scroll-body',\n 'waterflow',\n 'flow-item',\n 'share-element',\n 'cover-view',\n 'cover-image',\n // custom element\n 'match-media',\n];\nconst UVUE_WEB_BUILT_IN_TAGS = [\n 'list-view',\n 'list-item',\n 'sticky-section',\n 'sticky-header',\n 'cloud-db-element',\n].map((tag) => 'uni-' + tag);\nconst UVUE_IOS_BUILT_IN_TAGS = [\n 'scroll-view',\n 'web-view',\n 'slider',\n 'form',\n 'switch',\n];\nconst UVUE_HARMONY_BUILT_IN_TAGS = [\n // TODO 列出完整列表\n ...BUILT_IN_TAG_NAMES,\n 'volume-panel',\n];\nconst NVUE_U_BUILT_IN_TAGS = [\n 'u-text',\n 'u-image',\n 'u-input',\n 'u-textarea',\n 'u-video',\n 'u-web-view',\n 'u-slider',\n 'u-ad',\n 'u-ad-draw',\n 'u-rich-text',\n];\nconst UVUE_WEB_BUILT_IN_CUSTOM_ELEMENTS = ['match-media'];\nconst UNI_UI_CONFLICT_TAGS = ['list-item'].map((tag) => 'uni-' + tag);\nfunction isBuiltInComponent(tag) {\n if (UNI_UI_CONFLICT_TAGS.indexOf(tag) !== -1) {\n return false;\n }\n // h5 平台会被转换为 v-uni-\n const realTag = 'uni-' + tag.replace('v-uni-', '');\n // TODO 区分x和非x\n return (BUILT_IN_TAGS.indexOf(realTag) !== -1 ||\n UVUE_WEB_BUILT_IN_TAGS.indexOf(realTag) !== -1);\n}\nfunction isH5CustomElement(tag, isX = false) {\n if (isX && UVUE_WEB_BUILT_IN_TAGS.indexOf(tag) !== -1) {\n return true;\n }\n return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1;\n}\nfunction isUniXElement(name) {\n return /^I?Uni.*Element(?:Impl)?$/.test(name);\n}\nfunction isH5NativeTag(tag) {\n return (tag !== 'head' &&\n (isHTMLTag(tag) || isSVGTag(tag)) &&\n !isBuiltInComponent(tag));\n}\nfunction isAppNativeTag(tag) {\n return isHTMLTag(tag) || isSVGTag(tag) || isBuiltInComponent(tag);\n}\nconst NVUE_CUSTOM_COMPONENTS = [\n 'ad',\n 'ad-draw',\n 'button',\n 'checkbox-group',\n 'checkbox',\n 'form',\n 'icon',\n 'label',\n 'movable-area',\n 'movable-view',\n 'navigator',\n 'picker',\n 'progress',\n 'radio-group',\n 'radio',\n 'rich-text',\n 'swiper-item',\n 'swiper',\n 'switch',\n 'slider',\n 'picker-view',\n 'picker-view-column',\n];\n// 内置的easycom组件\nconst UVUE_BUILT_IN_EASY_COMPONENTS = [\n 'map',\n 'camera',\n 'live-player',\n 'live-pusher',\n];\nfunction isAppUVueBuiltInEasyComponent(tag) {\n return UVUE_BUILT_IN_EASY_COMPONENTS.includes(tag);\n}\n// 主要是指前端实现的组件列表\nconst UVUE_CUSTOM_COMPONENTS = [\n ...NVUE_CUSTOM_COMPONENTS,\n ...UVUE_BUILT_IN_EASY_COMPONENTS,\n];\nfunction isAppUVueNativeTag(tag) {\n // 前端实现的内置组件都会注册一个根组件\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n if (UVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_CUSTOM_COMPONENTS.includes(tag)) {\n return false;\n }\n if (isBuiltInComponent(tag)) {\n return true;\n }\n // u-text,u-video...\n if (NVUE_U_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isAppIOSUVueNativeTag(tag) {\n // 前端实现的内置组件都会注册一个根组件\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n if (NVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_IOS_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isAppHarmonyUVueNativeTag(tag) {\n // video 目前是easycom实现的\n if (tag === 'video' || tag === 'map') {\n return false;\n }\n // 前端实现的内置组件都会注册一个根组件\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n if (NVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (UVUE_HARMONY_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isAppNVueNativeTag(tag) {\n if (NVUE_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n if (NVUE_CUSTOM_COMPONENTS.includes(tag)) {\n return false;\n }\n if (isBuiltInComponent(tag)) {\n return true;\n }\n // u-text,u-video...\n if (NVUE_U_BUILT_IN_TAGS.includes(tag)) {\n return true;\n }\n return false;\n}\nfunction isMiniProgramNativeTag(tag) {\n return isBuiltInComponent(tag);\n}\nfunction isMiniProgramUVueNativeTag(tag) {\n // 小程序平台内置的自定义元素,会被转换为 view\n if (tag.startsWith('uni-') && tag.endsWith('-element')) {\n return true;\n }\n return isBuiltInComponent(tag);\n}\nfunction createIsCustomElement(tags = []) {\n return function isCustomElement(tag) {\n return tags.includes(tag);\n };\n}\nfunction isComponentTag(tag) {\n return tag[0].toLowerCase() + tag.slice(1) === 'component';\n}\nconst COMPONENT_SELECTOR_PREFIX = 'uni-';\nconst COMPONENT_PREFIX = 'v-' + COMPONENT_SELECTOR_PREFIX;\n// TODO 是否还存在其他需要特殊处理的 void 标签?\nconst APP_VOID_TAGS = ['textarea'];\nfunction isAppVoidTag(tag) {\n return APP_VOID_TAGS.includes(tag) || isVoidTag(tag);\n}\n\nconst LINEFEED = '\\n';\nconst NAVBAR_HEIGHT = 44;\nconst TABBAR_HEIGHT = 50;\nconst ON_REACH_BOTTOM_DISTANCE = 50;\nconst RESPONSIVE_MIN_WIDTH = 768;\nconst UNI_STORAGE_LOCALE = 'UNI_LOCALE';\n// quickapp-webview 不能使用 default 作为插槽名称\nconst SLOT_DEFAULT_NAME = 'd';\nconst COMPONENT_NAME_PREFIX = 'VUni';\nconst I18N_JSON_DELIMITERS = ['%', '%'];\nconst PRIMARY_COLOR = '#007aff';\nconst SELECTED_COLOR = '#0062cc'; // 选中的颜色,如选项卡默认的选中颜色\nconst BACKGROUND_COLOR = '#f7f7f7'; // 背景色,如标题栏默认背景色\nconst UNI_SSR = '__uniSSR';\nconst UNI_SSR_TITLE = 'title';\nconst UNI_SSR_STORE = 'store';\nconst UNI_SSR_DATA = 'data';\nconst UNI_SSR_GLOBAL_DATA = 'globalData';\nconst SCHEME_RE = /^([a-z-]+:)?\\/\\//i;\nconst DATA_RE = /^data:.*,.*/;\nconst WEB_INVOKE_APPSERVICE = 'WEB_INVOKE_APPSERVICE';\nconst WXS_PROTOCOL = 'wxs://';\nconst JSON_PROTOCOL = 'json://';\nconst WXS_MODULES = 'wxsModules';\nconst RENDERJS_MODULES = 'renderjsModules';\n// lifecycle\n// App and Page\nconst ON_SHOW = 'onShow';\nconst ON_HIDE = 'onHide';\n//App\nconst ON_LAUNCH = 'onLaunch';\nconst ON_ERROR = 'onError';\nconst ON_THEME_CHANGE = 'onThemeChange';\nconst OFF_THEME_CHANGE = 'offThemeChange';\nconst ON_HOST_THEME_CHANGE = 'onHostThemeChange';\nconst OFF_HOST_THEME_CHANGE = 'offHostThemeChange';\nconst ON_KEYBOARD_HEIGHT_CHANGE = 'onKeyboardHeightChange';\nconst ON_PAGE_NOT_FOUND = 'onPageNotFound';\nconst ON_UNHANDLE_REJECTION = 'onUnhandledRejection';\nconst ON_LAST_PAGE_BACK_PRESS = 'onLastPageBackPress';\nconst ON_EXIT = 'onExit';\n//Page\nconst ON_LOAD = 'onLoad';\nconst ON_READY = 'onReady';\nconst ON_UNLOAD = 'onUnload';\n// 百度特有\nconst ON_INIT = 'onInit';\n// 微信特有\nconst ON_SAVE_EXIT_STATE = 'onSaveExitState';\nconst ON_RESIZE = 'onResize';\nconst ON_BACK_PRESS = 'onBackPress';\nconst ON_PAGE_SCROLL = 'onPageScroll';\nconst ON_TAB_ITEM_TAP = 'onTabItemTap';\nconst ON_REACH_BOTTOM = 'onReachBottom';\nconst ON_PULL_DOWN_REFRESH = 'onPullDownRefresh';\nconst ON_SHARE_TIMELINE = 'onShareTimeline';\nconst ON_SHARE_CHAT = 'onShareChat'; // xhs-share\nconst ON_ADD_TO_FAVORITES = 'onAddToFavorites';\nconst ON_SHARE_APP_MESSAGE = 'onShareAppMessage';\n// navigationBar\nconst ON_NAVIGATION_BAR_BUTTON_TAP = 'onNavigationBarButtonTap';\nconst ON_NAVIGATION_BAR_CHANGE = 'onNavigationBarChange';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED = 'onNavigationBarSearchInputClicked';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED = 'onNavigationBarSearchInputChanged';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED = 'onNavigationBarSearchInputConfirmed';\nconst ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED = 'onNavigationBarSearchInputFocusChanged';\n// framework\nconst ON_APP_ENTER_FOREGROUND = 'onAppEnterForeground';\nconst ON_APP_ENTER_BACKGROUND = 'onAppEnterBackground';\nconst ON_WEB_INVOKE_APP_SERVICE = 'onWebInvokeAppService';\nconst ON_WXS_INVOKE_CALL_METHOD = 'onWxsInvokeCallMethod';\n// mergeVirtualHostAttributes\nconst VIRTUAL_HOST_STYLE = 'virtualHostStyle';\nconst VIRTUAL_HOST_CLASS = 'virtualHostClass';\nconst VIRTUAL_HOST_HIDDEN = 'virtualHostHidden';\nconst VIRTUAL_HOST_ID = 'virtualHostId';\n\nfunction cache(fn) {\n const cache = Object.create(null);\n return (str) => {\n const hit = cache[str];\n return hit || (cache[str] = fn(str));\n };\n}\nfunction cacheStringFunction(fn) {\n return cache(fn);\n}\nfunction getLen(str = '') {\n return ('' + str).replace(/[^\\x00-\\xff]/g, '**').length;\n}\nfunction hasLeadingSlash(str) {\n return str.indexOf('/') === 0;\n}\nfunction addLeadingSlash(str) {\n return hasLeadingSlash(str) ? str : '/' + str;\n}\nfunction removeLeadingSlash(str) {\n return hasLeadingSlash(str) ? str.slice(1) : str;\n}\nconst invokeArrayFns = (fns, arg) => {\n let ret;\n for (let i = 0; i < fns.length; i++) {\n ret = fns[i](arg);\n }\n return ret;\n};\nfunction updateElementStyle(element, styles) {\n for (const attrName in styles) {\n element.style[attrName] = styles[attrName];\n }\n}\nfunction once(fn, ctx = null) {\n let res;\n return ((...args) => {\n if (fn) {\n res = fn.apply(ctx, args);\n fn = null;\n }\n return res;\n });\n}\nconst sanitise = (val) => (val && JSON.parse(JSON.stringify(val))) || val;\nconst _completeValue = (value) => (value > 9 ? value : '0' + value);\nfunction formatDateTime({ date = new Date(), mode = 'date' }) {\n if (mode === 'time') {\n return (_completeValue(date.getHours()) + ':' + _completeValue(date.getMinutes()));\n }\n else {\n return (date.getFullYear() +\n '-' +\n _completeValue(date.getMonth() + 1) +\n '-' +\n _completeValue(date.getDate()));\n }\n}\nfunction callOptions(options, data) {\n options = options || {};\n if (isString(data)) {\n data = {\n errMsg: data,\n };\n }\n if (/:ok$/.test(data.errMsg)) {\n if (isFunction(options.success)) {\n options.success(data);\n }\n }\n else {\n if (isFunction(options.fail)) {\n options.fail(data);\n }\n }\n if (isFunction(options.complete)) {\n options.complete(data);\n }\n}\nfunction getValueByDataPath(obj, path) {\n if (!isString(path)) {\n return;\n }\n path = path.replace(/\\[(\\d+)\\]/g, '.$1');\n const parts = path.split('.');\n let key = parts[0];\n if (!obj) {\n obj = {};\n }\n if (parts.length === 1) {\n return obj[key];\n }\n return getValueByDataPath(obj[key], parts.slice(1).join('.'));\n}\nfunction sortObject(obj) {\n let sortObj = {};\n if (isPlainObject(obj)) {\n Object.keys(obj)\n .sort()\n .forEach((key) => {\n const _key = key;\n sortObj[_key] = obj[_key];\n });\n }\n return !Object.keys(sortObj) ? obj : sortObj;\n}\nfunction getGlobalOnce() {\n if (typeof globalThis !== 'undefined') {\n return globalThis;\n }\n // worker\n if (typeof self !== 'undefined') {\n return self;\n }\n // browser\n if (typeof window !== 'undefined') {\n return window;\n }\n // nodejs\n // if (typeof global !== 'undefined') {\n // return global\n // }\n function g() {\n return this;\n }\n if (typeof g() !== 'undefined') {\n return g();\n }\n return (function () {\n return new Function('return this')();\n })();\n}\nlet g = undefined;\nfunction getGlobal() {\n if (g) {\n return g;\n }\n g = getGlobalOnce();\n return g;\n}\n\nfunction isComponentInternalInstance(vm) {\n return !!vm.appContext;\n}\nfunction resolveComponentInstance(instance) {\n return (instance &&\n (isComponentInternalInstance(instance) ? instance.proxy : instance));\n}\nfunction resolveOwnerVm(vm) {\n if (!vm) {\n return;\n }\n let componentName = vm.type.name;\n while (componentName && isBuiltInComponent(hyphenate(componentName))) {\n // ownerInstance 内置组件需要使用父 vm\n vm = vm.parent;\n componentName = vm.type.name;\n }\n return vm.proxy;\n}\nfunction isElement(el) {\n // Element\n return el.nodeType === 1;\n}\nfunction resolveOwnerEl(instance, multi = false) {\n const { vnode } = instance;\n if (isElement(vnode.el)) {\n return multi ? (vnode.el ? [vnode.el] : []) : vnode.el;\n }\n const { subTree } = instance;\n // ShapeFlags.ARRAY_CHILDREN = 1<<4\n if (subTree.shapeFlag & 16) {\n const elemVNodes = subTree.children.filter((vnode) => vnode.el && isElement(vnode.el));\n if (elemVNodes.length > 0) {\n if (multi) {\n return elemVNodes.map((node) => node.el);\n }\n return elemVNodes[0].el;\n }\n }\n return multi ? (vnode.el ? [vnode.el] : []) : vnode.el;\n}\nfunction dynamicSlotName(name) {\n return name === 'default' ? SLOT_DEFAULT_NAME : name;\n}\nconst customizeRE = /:/g;\nfunction customizeEvent(str) {\n return camelize(str.replace(customizeRE, '-'));\n}\nfunction normalizeStyle(value) {\n const g = getGlobal();\n if (g && g.UTSJSONObject && value instanceof g.UTSJSONObject) {\n const styleObject = {};\n g.UTSJSONObject.keys(value).forEach((key) => {\n styleObject[key] = value[key];\n });\n return normalizeStyle$1(styleObject);\n }\n else if (value instanceof Map) {\n const styleObject = {};\n value.forEach((value, key) => {\n styleObject[key] = value;\n });\n return normalizeStyle$1(styleObject);\n }\n else if (isString(value)) {\n return parseStringStyle(value);\n }\n else if (isArray(value)) {\n const res = {};\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n const normalized = isString(item)\n ? parseStringStyle(item)\n : normalizeStyle(item);\n if (normalized) {\n for (const key in normalized) {\n res[key] = normalized[key];\n }\n }\n }\n return res;\n }\n else {\n return normalizeStyle$1(value);\n }\n}\nfunction normalizeClass(value) {\n let res = '';\n const g = getGlobal();\n if (g && g.UTSJSONObject && value instanceof g.UTSJSONObject) {\n g.UTSJSONObject.keys(value).forEach((key) => {\n if (value[key]) {\n res += key + ' ';\n }\n });\n }\n else if (value instanceof Map) {\n value.forEach((value, key) => {\n if (value) {\n res += key + ' ';\n }\n });\n }\n else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const normalized = normalizeClass(value[i]);\n if (normalized) {\n res += normalized + ' ';\n }\n }\n }\n else {\n res = normalizeClass$1(value);\n }\n return res.trim();\n}\nfunction normalizeProps(props) {\n if (!props)\n return null;\n let { class: klass, style } = props;\n if (klass && !isString(klass)) {\n props.class = normalizeClass(klass);\n }\n if (style) {\n props.style = normalizeStyle(style);\n }\n return props;\n}\n\nlet lastLogTime = 0;\nfunction formatLog(module, ...args) {\n const now = Date.now();\n const diff = lastLogTime ? now - lastLogTime : 0;\n lastLogTime = now;\n return `[${now}][${diff}ms][${module}]:${args\n .map((arg) => JSON.stringify(arg))\n .join(' ')}`;\n}\n\nfunction formatKey(key) {\n return camelize(key.substring(5));\n}\n// question/139181,增加副作用,避免 initCustomDataset 在 build 下被 tree-shaking\nconst initCustomDatasetOnce = /*#__PURE__*/ once((isBuiltInElement) => {\n isBuiltInElement =\n isBuiltInElement || ((el) => el.tagName.startsWith('UNI-'));\n const prototype = HTMLElement.prototype;\n const setAttribute = prototype.setAttribute;\n prototype.setAttribute = function (key, value) {\n if (key.startsWith('data-') && isBuiltInElement(this)) {\n const dataset = this.__uniDataset ||\n (this.__uniDataset = {});\n dataset[formatKey(key)] = value;\n }\n setAttribute.call(this, key, value);\n };\n const removeAttribute = prototype.removeAttribute;\n prototype.removeAttribute = function (key) {\n if (this.__uniDataset &&\n key.startsWith('data-') &&\n isBuiltInElement(this)) {\n delete this.__uniDataset[formatKey(key)];\n }\n removeAttribute.call(this, key);\n };\n});\nfunction getCustomDataset(el) {\n return extend({}, el.dataset, el.__uniDataset);\n}\n\nconst unitRE = new RegExp(`\"[^\"]+\"|'[^']+'|url\\\\([^)]+\\\\)|(\\\\d*\\\\.?\\\\d+)[r|u]px`, 'g');\nfunction toFixed(number, precision) {\n const multiplier = Math.pow(10, precision + 1);\n const wholeNumber = Math.floor(number * multiplier);\n return (Math.round(wholeNumber / 10) * 10) / multiplier;\n}\nconst defaultRpx2Unit = {\n unit: 'rem',\n unitRatio: 10 / 320,\n unitPrecision: 5,\n};\nconst defaultMiniProgramRpx2Unit = {\n unit: 'rpx',\n unitRatio: 1,\n unitPrecision: 1,\n};\nconst defaultNVueRpx2Unit = defaultMiniProgramRpx2Unit;\nfunction createRpx2Unit(unit, unitRatio, unitPrecision) {\n // ignore: rpxCalcIncludeWidth\n return (val) => val.replace(unitRE, (m, $1) => {\n if (!$1) {\n return m;\n }\n if (unitRatio === 1) {\n return `${$1}${unit}`;\n }\n const value = toFixed(parseFloat($1) * unitRatio, unitPrecision);\n return value === 0 ? '0' : `${value}${unit}`;\n });\n}\n\nfunction passive(passive) {\n return { passive };\n}\nfunction normalizeDataset(el) {\n // TODO\n return JSON.parse(JSON.stringify(el.dataset || {}));\n}\nfunction normalizeTarget(el) {\n const { id, offsetTop, offsetLeft } = el;\n return {\n id,\n dataset: getCustomDataset(el),\n offsetTop,\n offsetLeft,\n };\n}\nfunction addFont(family, source, desc) {\n const fonts = document.fonts;\n if (fonts) {\n const fontFace = new FontFace(family, source, desc);\n return fontFace.load().then(() => {\n fonts.add && fonts.add(fontFace);\n });\n }\n return new Promise((resolve) => {\n const style = document.createElement('style');\n const values = [];\n if (desc) {\n const { style, weight, stretch, unicodeRange, variant, featureSettings } = desc;\n style && values.push(`font-style:${style}`);\n weight && values.push(`font-weight:${weight}`);\n stretch && values.push(`font-stretch:${stretch}`);\n unicodeRange && values.push(`unicode-range:${unicodeRange}`);\n variant && values.push(`font-variant:${variant}`);\n featureSettings && values.push(`font-feature-settings:${featureSettings}`);\n }\n style.innerText = `@font-face{font-family:\"${family}\";src:${source};${values.join(';')}}`;\n document.head.appendChild(style);\n resolve();\n });\n}\nfunction scrollTo(scrollTop, duration, isH5) {\n if (isString(scrollTop)) {\n const el = document.querySelector(scrollTop);\n if (el) {\n const { top } = el.getBoundingClientRect();\n scrollTop = top + window.pageYOffset;\n // 如果存在,减去 高度\n const pageHeader = document.querySelector('uni-page-head');\n if (pageHeader) {\n scrollTop -= pageHeader.offsetHeight;\n }\n }\n }\n if (scrollTop < 0) {\n scrollTop = 0;\n }\n const documentElement = document.documentElement;\n const { clientHeight, scrollHeight } = documentElement;\n scrollTop = Math.min(scrollTop, scrollHeight - clientHeight);\n if (duration === 0) {\n // 部分浏览器(比如微信)中 scrollTop 的值需要通过 document.body 来控制\n documentElement.scrollTop = document.body.scrollTop = scrollTop;\n return;\n }\n if (window.scrollY === scrollTop) {\n return;\n }\n const scrollTo = (duration) => {\n if (duration <= 0) {\n window.scrollTo(0, scrollTop);\n return;\n }\n const distaince = scrollTop - window.scrollY;\n requestAnimationFrame(function () {\n window.scrollTo(0, window.scrollY + (distaince / duration) * 10);\n scrollTo(duration - 10);\n });\n };\n scrollTo(duration);\n}\n\nconst encode = encodeURIComponent;\nfunction stringifyQuery(obj, encodeStr = encode) {\n const res = obj\n ? Object.keys(obj)\n .map((key) => {\n let val = obj[key];\n if (typeof val === undefined || val === null) {\n val = '';\n }\n else if (isPlainObject(val)) {\n val = JSON.stringify(val);\n }\n return encodeStr(key) + '=' + encodeStr(val);\n })\n .filter((x) => x.length > 0)\n .join('&')\n : null;\n return res ? `?${res}` : '';\n}\n/**\n * Decode text using `decodeURIComponent`. Returns the original text if it\n * fails.\n *\n * @param text - string to decode\n * @returns decoded string\n */\nfunction decode(text) {\n try {\n return decodeURIComponent('' + text);\n }\n catch (err) { }\n return '' + text;\n}\nfunction decodedQuery(query = {}) {\n const decodedQuery = {};\n Object.keys(query).forEach((name) => {\n try {\n decodedQuery[name] = decode(query[name]);\n }\n catch (e) {\n decodedQuery[name] = query[name];\n }\n });\n return decodedQuery;\n}\nconst PLUS_RE = /\\+/g; // %2B\n/**\n * https://github.com/vuejs/vue-router-next/blob/master/src/query.ts\n * @internal\n *\n * @param search - search string to parse\n * @returns a query object\n */\nfunction parseQuery(search) {\n const query = {};\n // avoid creating an object with an empty key and empty value\n // because of split('&')\n if (search === '' || search === '?')\n return query;\n const hasLeadingIM = search[0] === '?';\n const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&');\n for (let i = 0; i < searchParams.length; ++i) {\n // pre decode the + into space\n const searchParam = searchParams[i].replace(PLUS_RE, ' ');\n // allow the = character\n let eqPos = searchParam.indexOf('=');\n let key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos));\n let value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1));\n if (key in query) {\n // an extra variable for ts types\n let currentValue = query[key];\n if (!isArray(currentValue)) {\n currentValue = query[key] = [currentValue];\n }\n currentValue.push(value);\n }\n else {\n query[key] = value;\n }\n }\n return query;\n}\n\nfunction parseUrl(url) {\n const [path, querystring] = url.split('?', 2);\n return {\n path,\n query: parseQuery(querystring || ''),\n };\n}\n\nfunction parseNVueDataset(attr) {\n const dataset = {};\n if (attr) {\n Object.keys(attr).forEach((key) => {\n if (key.indexOf('data-') === 0) {\n dataset[key.replace('data-', '')] = attr[key];\n }\n });\n }\n return dataset;\n}\n\nfunction plusReady(callback) {\n if (!isFunction(callback)) {\n return;\n }\n if (window.plus) {\n return callback();\n }\n document.addEventListener('plusready', callback);\n}\n\nclass DOMException extends Error {\n constructor(message) {\n super(message);\n this.name = 'DOMException';\n }\n}\n\nfunction normalizeEventType(type, options) {\n if (options) {\n if (options.capture) {\n type += 'Capture';\n }\n if (options.once) {\n type += 'Once';\n }\n if (options.passive) {\n type += 'Passive';\n }\n }\n return `on${capitalize(camelize(type))}`;\n}\nclass UniEvent {\n constructor(type, opts) {\n this.defaultPrevented = false;\n this.timeStamp = Date.now();\n this._stop = false;\n this._end = false;\n this.type = type;\n this.bubbles = !!opts.bubbles;\n this.cancelable = !!opts.cancelable;\n }\n preventDefault() {\n this.defaultPrevented = true;\n }\n stopImmediatePropagation() {\n this._end = this._stop = true;\n }\n stopPropagation() {\n this._stop = true;\n }\n}\nfunction createUniEvent(evt) {\n if (evt instanceof UniEvent) {\n return evt;\n }\n const [type] = parseEventName(evt.type);\n const uniEvent = new UniEvent(type, {\n bubbles: false,\n cancelable: false,\n });\n extend(uniEvent, evt);\n return uniEvent;\n}\nclass UniEventTarget {\n constructor() {\n this.listeners = Object.create(null);\n }\n dispatchEvent(evt) {\n const listeners = this.listeners[evt.type];\n if (!listeners) {\n if ((process.env.NODE_ENV !== 'production')) {\n console.error(formatLog('dispatchEvent', this.nodeId), evt.type, 'not found');\n }\n return false;\n }\n // 格式化事件类型\n const event = createUniEvent(evt);\n const len = listeners.length;\n for (let i = 0; i < len; i++) {\n listeners[i].call(this, event);\n if (event._end) {\n break;\n }\n }\n return event.cancelable && event.defaultPrevented;\n }\n addEventListener(type, listener, options) {\n type = normalizeEventType(type, options);\n (this.listeners[type] || (this.listeners[type] = [])).push(listener);\n }\n removeEventListener(type, callback, options) {\n type = normalizeEventType(type, options);\n const listeners = this.listeners[type];\n if (!listeners) {\n return;\n }\n const index = listeners.indexOf(callback);\n if (index > -1) {\n listeners.splice(index, 1);\n }\n }\n}\nconst optionsModifierRE = /(?:Once|Passive|Capture)$/;\nfunction parseEventName(name) {\n let options;\n if (optionsModifierRE.test(name)) {\n options = {};\n let m;\n while ((m = name.match(optionsModifierRE))) {\n name = name.slice(0, name.length - m[0].length);\n options[m[0].toLowerCase()] = true;\n }\n }\n return [hyphenate(name.slice(2)), options];\n}\n\nconst EventModifierFlags = /*#__PURE__*/ (() => {\n return {\n stop: 1,\n prevent: 1 << 1,\n self: 1 << 2,\n };\n})();\nfunction encodeModifier(modifiers) {\n let flag = 0;\n if (modifiers.includes('stop')) {\n flag |= EventModifierFlags.stop;\n }\n if (modifiers.includes('prevent')) {\n flag |= EventModifierFlags.prevent;\n }\n if (modifiers.includes('self')) {\n flag |= EventModifierFlags.self;\n }\n return flag;\n}\n\nconst NODE_TYPE_PAGE = 0;\nconst NODE_TYPE_ELEMENT = 1;\nconst NODE_TYPE_TEXT = 3;\nconst NODE_TYPE_COMMENT = 8;\nfunction sibling(node, type) {\n const { parentNode } = node;\n if (!parentNode) {\n return null;\n }\n const { childNodes } = parentNode;\n return childNodes[childNodes.indexOf(node) + (type === 'n' ? 1 : -1)] || null;\n}\nfunction removeNode(node) {\n const { parentNode } = node;\n if (parentNode) {\n const { childNodes } = parentNode;\n const index = childNodes.indexOf(node);\n if (index > -1) {\n node.parentNode = null;\n childNodes.splice(index, 1);\n }\n }\n}\nfunction checkNodeId(node) {\n if (!node.nodeId && node.pageNode) {\n node.nodeId = node.pageNode.genId();\n }\n}\n// 为优化性能,各平台不使用proxy来实现node的操作拦截,而是直接通过pageNode定制\nclass UniNode extends UniEventTarget {\n constructor(nodeType, nodeName, container) {\n super();\n this.pageNode = null;\n this.parentNode = null;\n this._text = null;\n if (container) {\n const { pageNode } = container;\n if (pageNode) {\n this.pageNode = pageNode;\n this.nodeId = pageNode.genId();\n !pageNode.isUnmounted && pageNode.onCreate(this, nodeName);\n }\n }\n this.nodeType = nodeType;\n this.nodeName = nodeName;\n this.childNodes = [];\n }\n get firstChild() {\n return this.childNodes[0] || null;\n }\n get lastChild() {\n const { childNodes } = this;\n const length = childNodes.length;\n return length ? childNodes[length - 1] : null;\n }\n get nextSibling() {\n return sibling(this, 'n');\n }\n get nodeValue() {\n return null;\n }\n set nodeValue(_val) { }\n get textContent() {\n return this._text || '';\n }\n set textContent(text) {\n this._text = text;\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onTextContent(this, text);\n }\n }\n get parentElement() {\n const { parentNode } = this;\n if (parentNode && parentNode.nodeType === NODE_TYPE_ELEMENT) {\n return parentNode;\n }\n return null;\n }\n get previousSibling() {\n return sibling(this, 'p');\n }\n appendChild(newChild) {\n return this.insertBefore(newChild, null);\n }\n cloneNode(deep) {\n const cloned = extend(Object.create(Object.getPrototypeOf(this)), this);\n const { attributes } = cloned;\n if (attributes) {\n cloned.attributes = extend({}, attributes);\n }\n if (deep) {\n cloned.childNodes = cloned.childNodes.map((childNode) => childNode.cloneNode(true));\n }\n return cloned;\n }\n insertBefore(newChild, refChild) {\n // 先从现在的父节点移除(注意:不能触发onRemoveChild,否则会生成先remove该 id,再 insert)\n removeNode(newChild);\n newChild.pageNode = this.pageNode;\n newChild.parentNode = this;\n checkNodeId(newChild);\n const { childNodes } = this;\n if (refChild) {\n const index = childNodes.indexOf(refChild);\n if (index === -1) {\n throw new DOMException(`Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.`);\n }\n childNodes.splice(index, 0, newChild);\n }\n else {\n childNodes.push(newChild);\n }\n return this.pageNode && !this.pageNode.isUnmounted\n ? this.pageNode.onInsertBefore(this, newChild, refChild)\n : newChild;\n }\n removeChild(oldChild) {\n const { childNodes } = this;\n const index = childNodes.indexOf(oldChild);\n if (index === -1) {\n throw new DOMException(`Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.`);\n }\n oldChild.parentNode = null;\n childNodes.splice(index, 1);\n return this.pageNode && !this.pageNode.isUnmounted\n ? this.pageNode.onRemoveChild(oldChild)\n : oldChild;\n }\n}\nconst ATTR_CLASS = 'class';\nconst ATTR_STYLE = 'style';\nconst ATTR_INNER_HTML = 'innerHTML';\nconst ATTR_TEXT_CONTENT = 'textContent';\nconst ATTR_V_SHOW = '.vShow';\nconst ATTR_V_OWNER_ID = '.vOwnerId';\nconst ATTR_V_RENDERJS = '.vRenderjs';\nconst ATTR_CHANGE_PREFIX = 'change:';\nclass UniBaseNode extends UniNode {\n constructor(nodeType, nodeName, container) {\n super(nodeType, nodeName, container);\n this.attributes = Object.create(null);\n this.style = null;\n this.vShow = null;\n this._html = null;\n }\n get className() {\n return (this.attributes[ATTR_CLASS] || '');\n }\n set className(val) {\n this.setAttribute(ATTR_CLASS, val);\n }\n get innerHTML() {\n return '';\n }\n set innerHTML(html) {\n this._html = html;\n }\n addEventListener(type, listener, options) {\n super.addEventListener(type, listener, options);\n if (this.pageNode && !this.pageNode.isUnmounted) {\n if (listener.wxsEvent) {\n this.pageNode.onAddWxsEvent(this, normalizeEventType(type, options), listener.wxsEvent, encodeModifier(listener.modifiers || []));\n }\n else {\n this.pageNode.onAddEvent(this, normalizeEventType(type, options), encodeModifier(listener.modifiers || []));\n }\n }\n }\n removeEventListener(type, callback, options) {\n super.removeEventListener(type, callback, options);\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onRemoveEvent(this, normalizeEventType(type, options));\n }\n }\n getAttribute(qualifiedName) {\n if (qualifiedName === ATTR_STYLE) {\n return this.style;\n }\n return this.attributes[qualifiedName];\n }\n removeAttribute(qualifiedName) {\n if (qualifiedName == ATTR_STYLE) {\n this.style = null;\n }\n else {\n delete this.attributes[qualifiedName];\n }\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onRemoveAttribute(this, qualifiedName);\n }\n }\n setAttribute(qualifiedName, value) {\n if (qualifiedName === ATTR_STYLE) {\n this.style = value;\n }\n else {\n this.attributes[qualifiedName] = value;\n }\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onSetAttribute(this, qualifiedName, value);\n }\n }\n toJSON({ attr, normalize, } = {}) {\n const { attributes, style, listeners, _text } = this;\n const res = {};\n if (Object.keys(attributes).length) {\n res.a = normalize ? normalize(attributes) : attributes;\n }\n const events = Object.keys(listeners);\n if (events.length) {\n let w = undefined;\n const e = {};\n events.forEach((name) => {\n const handlers = listeners[name];\n if (handlers.length) {\n // 可能存在多个 handler 且不同 modifiers 吗?\n const { wxsEvent, modifiers } = handlers[0];\n const modifier = encodeModifier(modifiers || []);\n if (!wxsEvent) {\n e[name] = modifier;\n }\n else {\n if (!w) {\n w = {};\n }\n w[name] = [normalize ? normalize(wxsEvent) : wxsEvent, modifier];\n }\n }\n });\n res.e = normalize ? normalize(e, false) : e;\n if (w) {\n res.w = normalize ? normalize(w, false) : w;\n }\n }\n if (style !== null) {\n res.s = normalize ? normalize(style) : style;\n }\n if (!attr) {\n res.i = this.nodeId;\n res.n = this.nodeName;\n }\n if (_text !== null) {\n res.t = normalize ? normalize(_text) : _text;\n }\n return res;\n }\n}\n\nclass UniCommentNode extends UniNode {\n constructor(text, container) {\n super(NODE_TYPE_COMMENT, '#comment', container);\n this._text = (process.env.NODE_ENV !== 'production') ? text : '';\n }\n toJSON(opts = {}) {\n // 暂时不传递 text 到 view 层,没啥意义,节省点数据量\n return opts.attr\n ? {}\n : {\n i: this.nodeId,\n };\n // return opts.attr\n // ? { t: this._text as string }\n // : {\n // i: this.nodeId!,\n // t: this._text as string,\n // }\n }\n}\n\nclass UniElement extends UniBaseNode {\n constructor(nodeName, container) {\n super(NODE_TYPE_ELEMENT, nodeName.toUpperCase(), container);\n this.tagName = this.nodeName;\n }\n}\nclass UniInputElement extends UniElement {\n get value() {\n return this.getAttribute('value');\n }\n set value(val) {\n this.setAttribute('value', val);\n }\n}\nclass UniTextAreaElement extends UniInputElement {\n}\n\nclass UniTextNode extends UniBaseNode {\n constructor(text, container) {\n super(NODE_TYPE_TEXT, '#text', container);\n this._text = text;\n }\n get nodeValue() {\n return this._text || '';\n }\n set nodeValue(text) {\n this._text = text;\n if (this.pageNode && !this.pageNode.isUnmounted) {\n this.pageNode.onNodeValue(this, text);\n }\n }\n}\n\nconst forcePatchProps = {\n AD: ['data'],\n 'AD-DRAW': ['data'],\n 'LIVE-PLAYER': ['picture-in-picture-mode'],\n MAP: [\n 'markers',\n 'polyline',\n 'circles',\n 'controls',\n 'include-points',\n 'polygons',\n ],\n PICKER: ['range', 'value'],\n 'PICKER-VIEW': ['value'],\n 'RICH-TEXT': ['nodes'],\n VIDEO: ['danmu-list', 'header'],\n 'WEB-VIEW': ['webview-styles'],\n};\nconst forcePatchPropKeys = ['animation'];\n\nconst forcePatchProp = (el, key) => {\n if (forcePatchPropKeys.indexOf(key) > -1) {\n return true;\n }\n const keys = forcePatchProps[el.nodeName];\n if (keys && keys.indexOf(key) > -1) {\n return true;\n }\n return false;\n};\n\nconst ACTION_TYPE_PAGE_CREATE = 1;\nconst ACTION_TYPE_PAGE_CREATED = 2;\nconst ACTION_TYPE_CREATE = 3;\nconst ACTION_TYPE_INSERT = 4;\nconst ACTION_TYPE_REMOVE = 5;\nconst ACTION_TYPE_SET_ATTRIBUTE = 6;\nconst ACTION_TYPE_REMOVE_ATTRIBUTE = 7;\nconst ACTION_TYPE_ADD_EVENT = 8;\nconst ACTION_TYPE_REMOVE_EVENT = 9;\nconst ACTION_TYPE_SET_TEXT = 10;\nconst ACTION_TYPE_ADD_WXS_EVENT = 12;\nconst ACTION_TYPE_PAGE_SCROLL = 15;\nconst ACTION_TYPE_EVENT = 20;\n\n/**\n * 需要手动传入 timer,主要是解决 App 平台的定制 timer\n */\nfunction debounce(fn, delay, { clearTimeout, setTimeout }) {\n let timeout;\n const newFn = function () {\n clearTimeout(timeout);\n const timerFn = () => fn.apply(this, arguments);\n timeout = setTimeout(timerFn, delay);\n };\n newFn.cancel = function () {\n clearTimeout(timeout);\n };\n return newFn;\n}\n\nclass EventChannel {\n constructor(id, events) {\n this.id = id;\n this.listener = {};\n this.emitCache = [];\n if (events) {\n Object.keys(events).forEach((name) => {\n this.on(name, events[name]);\n });\n }\n }\n emit(eventName, ...args) {\n const fns = this.listener[eventName];\n if (!fns) {\n return this.emitCache.push({\n eventName,\n args,\n });\n }\n fns.forEach((opt) => {\n opt.fn.apply(opt.fn, args);\n });\n this.listener[eventName] = fns.filter((opt) => opt.type !== 'once');\n }\n on(eventName, fn) {\n this._addListener(eventName, 'on', fn);\n this._clearCache(eventName);\n }\n once(eventName, fn) {\n this._addListener(eventName, 'once', fn);\n this._clearCache(eventName);\n }\n off(eventName, fn) {\n const fns = this.listener[eventName];\n if (!fns) {\n return;\n }\n if (fn) {\n for (let i = 0; i < fns.length;) {\n if (fns[i].fn === fn) {\n fns.splice(i, 1);\n i--;\n }\n i++;\n }\n }\n else {\n delete this.listener[eventName];\n }\n }\n _clearCache(eventName) {\n for (let index = 0; index < this.emitCache.length; index++) {\n const cache = this.emitCache[index];\n const _name = eventName\n ? cache.eventName === eventName\n ? eventName\n : null\n : cache.eventName;\n if (!_name)\n continue;\n const location = this.emit.apply(this, [_name, ...cache.args]);\n if (typeof location === 'number') {\n this.emitCache.pop();\n continue;\n }\n this.emitCache.splice(index, 1);\n index--;\n }\n }\n _addListener(eventName, type, fn) {\n (this.listener[eventName] || (this.listener[eventName] = [])).push({\n fn,\n type,\n });\n }\n}\n\nconst PAGE_HOOKS = [\n ON_INIT,\n ON_LOAD,\n ON_SHOW,\n ON_HIDE,\n ON_UNLOAD,\n ON_BACK_PRESS,\n ON_PAGE_SCROLL,\n ON_TAB_ITEM_TAP,\n ON_REACH_BOTTOM,\n ON_PULL_DOWN_REFRESH,\n ON_SHARE_TIMELINE,\n ON_SHARE_APP_MESSAGE,\n ON_SHARE_CHAT,\n ON_ADD_TO_FAVORITES,\n ON_SAVE_EXIT_STATE,\n ON_NAVIGATION_BAR_BUTTON_TAP,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED,\n];\nfunction isRootImmediateHook(name) {\n const PAGE_SYNC_HOOKS = [ON_LOAD, ON_SHOW];\n return PAGE_SYNC_HOOKS.indexOf(name) > -1;\n}\n// isRootImmediateHookX deprecated\nfunction isRootHook(name) {\n return PAGE_HOOKS.indexOf(name) > -1;\n}\nconst UniLifecycleHooks = [\n ON_SHOW,\n ON_HIDE,\n ON_LAUNCH,\n ON_ERROR,\n ON_THEME_CHANGE,\n ON_PAGE_NOT_FOUND,\n ON_UNHANDLE_REJECTION,\n ON_EXIT,\n ON_INIT,\n ON_LOAD,\n ON_READY,\n ON_UNLOAD,\n ON_RESIZE,\n ON_BACK_PRESS,\n ON_PAGE_SCROLL,\n ON_TAB_ITEM_TAP,\n ON_REACH_BOTTOM,\n ON_PULL_DOWN_REFRESH,\n ON_SHARE_TIMELINE,\n ON_ADD_TO_FAVORITES,\n ON_SHARE_APP_MESSAGE,\n ON_SHARE_CHAT,\n ON_SAVE_EXIT_STATE,\n ON_NAVIGATION_BAR_BUTTON_TAP,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED,\n ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED,\n];\nconst MINI_PROGRAM_PAGE_RUNTIME_HOOKS = /*#__PURE__*/ (() => {\n return {\n onPageScroll: 1,\n onShareAppMessage: 1 << 1,\n onShareTimeline: 1 << 2,\n };\n})();\nfunction isUniLifecycleHook(name, value, checkType = true) {\n // 检查类型\n if (checkType && !isFunction(value)) {\n return false;\n }\n if (UniLifecycleHooks.indexOf(name) > -1) {\n // 已预定义\n return true;\n }\n else if (name.indexOf('on') === 0) {\n // 以 on 开头\n return true;\n }\n return false;\n}\n\nlet vueApp;\nconst createVueAppHooks = [];\n/**\n * 提供 createApp 的回调事件,方便三方插件接收 App 对象,处理挂靠全局 mixin 之类的逻辑\n */\nfunction onCreateVueApp(hook) {\n // TODO 每个 nvue 页面都会触发\n if (vueApp) {\n return hook(vueApp);\n }\n createVueAppHooks.push(hook);\n}\nfunction invokeCreateVueAppHook(app) {\n vueApp = app;\n createVueAppHooks.forEach((hook) => hook(app));\n}\nconst invokeCreateErrorHandler = once((app, createErrorHandler) => {\n // 不再判断开发者是否监听了onError,直接返回 createErrorHandler,内部 errorHandler 会调用开发者自定义的 errorHandler,以及判断开发者是否监听了onError\n return createErrorHandler(app);\n});\n\nconst E = function () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n};\nE.prototype = {\n _id: 1,\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx,\n _id: this._id,\n });\n return this._id++;\n },\n once: function (name, callback, ctx) {\n var self = this;\n function listener() {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n }\n listener._ = callback;\n return this.on(name, listener, ctx);\n },\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n return this;\n },\n off: function (name, event) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n if (evts && event) {\n for (var i = evts.length - 1; i >= 0; i--) {\n if (evts[i].fn === event ||\n evts[i].fn._ === event ||\n evts[i]._id === event) {\n evts.splice(i, 1);\n break;\n }\n }\n liveEvents = evts;\n }\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n liveEvents.length ? (e[name] = liveEvents) : delete e[name];\n return this;\n },\n};\nvar E$1 = E;\n\nconst borderStyles = {\n black: 'rgba(0,0,0,0.4)',\n white: 'rgba(255,255,255,0.4)',\n};\nfunction normalizeTabBarStyles(borderStyle) {\n if (borderStyle && borderStyle in borderStyles) {\n return borderStyles[borderStyle];\n }\n return borderStyle;\n}\nfunction normalizeTitleColor(titleColor) {\n return titleColor === 'black' ? '#000000' : '#ffffff';\n}\nfunction resolveStringStyleItem(modeStyle, styleItem, key) {\n if (isString(styleItem) && styleItem.startsWith('@')) {\n const _key = styleItem.replace('@', '');\n let _styleItem = modeStyle[_key] || styleItem;\n switch (key) {\n case 'titleColor':\n _styleItem = normalizeTitleColor(_styleItem);\n break;\n case 'borderStyle':\n _styleItem = normalizeTabBarStyles(_styleItem);\n break;\n }\n return _styleItem;\n }\n return styleItem;\n}\nfunction normalizeStyles(pageStyle, themeConfig = {}, mode = 'light') {\n const modeStyle = themeConfig[mode];\n const styles = {};\n if (typeof modeStyle === 'undefined' || !pageStyle)\n return pageStyle;\n Object.keys(pageStyle).forEach((key) => {\n const styleItem = pageStyle[key]; // Object Array String\n const parseStyleItem = () => {\n if (isPlainObject(styleItem))\n return normalizeStyles(styleItem, themeConfig, mode);\n if (isArray(styleItem))\n return styleItem.map((item) => {\n if (isPlainObject(item))\n return normalizeStyles(item, themeConfig, mode);\n return resolveStringStyleItem(modeStyle, item);\n });\n return resolveStringStyleItem(modeStyle, styleItem, key);\n };\n styles[key] = parseStyleItem();\n });\n return styles;\n}\n\nfunction getEnvLocale() {\n const { env } = process;\n const lang = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE;\n return (lang && lang.replace(/[.:].*/, '')) || 'en';\n}\n\nconst isStringIntegerKey = (key) => typeof key === 'string' &&\n key !== 'NaN' &&\n key[0] !== '-' &&\n '' + parseInt(key, 10) === key;\nconst isNumberIntegerKey = (key) => typeof key === 'number' &&\n !isNaN(key) &&\n key >= 0 &&\n parseInt(key + '', 10) === key;\n/**\n * 用于替代@vue/shared的isIntegerKey,原始方法在鸿蒙arkts中会引发bug。根本原因是arkts的数组的key是数字而不是字符串。\n * 目前这个方法使用的地方都和数组有关,切记不能挪作他用。\n * @param key\n * @returns\n */\nconst isIntegerKey = (key) => isNumberIntegerKey(key) || isStringIntegerKey(key);\n\nconst GLOBALS_ALLOWED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +\n 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +\n 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,' +\n 'uni';\nconst isGloballyAllowed = /*#__PURE__*/ makeMap(GLOBALS_ALLOWED);\n\nexport { ACTION_TYPE_ADD_EVENT, ACTION_TYPE_ADD_WXS_EVENT, ACTION_TYPE_CREATE, ACTION_TYPE_EVENT, ACTION_TYPE_INSERT, ACTION_TYPE_PAGE_CREATE, ACTION_TYPE_PAGE_CREATED, ACTION_TYPE_PAGE_SCROLL, ACTION_TYPE_REMOVE, ACTION_TYPE_REMOVE_ATTRIBUTE, ACTION_TYPE_REMOVE_EVENT, ACTION_TYPE_SET_ATTRIBUTE, ACTION_TYPE_SET_TEXT, ATTR_CHANGE_PREFIX, ATTR_CLASS, ATTR_INNER_HTML, ATTR_STYLE, ATTR_TEXT_CONTENT, ATTR_V_OWNER_ID, ATTR_V_RENDERJS, ATTR_V_SHOW, BACKGROUND_COLOR, BUILT_IN_TAGS, BUILT_IN_TAG_NAMES, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, DATA_RE, E$1 as Emitter, EventChannel, EventModifierFlags, I18N_JSON_DELIMITERS, JSON_PROTOCOL, LINEFEED, MINI_PROGRAM_PAGE_RUNTIME_HOOKS, NAVBAR_HEIGHT, NODE_TYPE_COMMENT, NODE_TYPE_ELEMENT, NODE_TYPE_PAGE, NODE_TYPE_TEXT, NVUE_BUILT_IN_TAGS, NVUE_U_BUILT_IN_TAGS, OFF_HOST_THEME_CHANGE, OFF_THEME_CHANGE, ON_ADD_TO_FAVORITES, ON_APP_ENTER_BACKGROUND, ON_APP_ENTER_FOREGROUND, ON_BACK_PRESS, ON_ERROR, ON_EXIT, ON_HIDE, ON_HOST_THEME_CHANGE, ON_INIT, ON_KEYBOARD_HEIGHT_CHANGE, ON_LAST_PAGE_BACK_PRESS, ON_LAUNCH, ON_LOAD, ON_NAVIGATION_BAR_BUTTON_TAP, ON_NAVIGATION_BAR_CHANGE, ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED, ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED, ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED, ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED, ON_PAGE_NOT_FOUND, ON_PAGE_SCROLL, ON_PULL_DOWN_REFRESH, ON_REACH_BOTTOM, ON_REACH_BOTTOM_DISTANCE, ON_READY, ON_RESIZE, ON_SAVE_EXIT_STATE, ON_SHARE_APP_MESSAGE, ON_SHARE_CHAT, ON_SHARE_TIMELINE, ON_SHOW, ON_TAB_ITEM_TAP, ON_THEME_CHANGE, ON_UNHANDLE_REJECTION, ON_UNLOAD, ON_WEB_INVOKE_APP_SERVICE, ON_WXS_INVOKE_CALL_METHOD, PLUS_RE, PRIMARY_COLOR, RENDERJS_MODULES, RESPONSIVE_MIN_WIDTH, SCHEME_RE, SELECTED_COLOR, SLOT_DEFAULT_NAME, TABBAR_HEIGHT, TAGS, UNI_SSR, UNI_SSR_DATA, UNI_SSR_GLOBAL_DATA, UNI_SSR_STORE, UNI_SSR_TITLE, UNI_STORAGE_LOCALE, UNI_UI_CONFLICT_TAGS, UVUE_BUILT_IN_TAGS, UVUE_HARMONY_BUILT_IN_TAGS, UVUE_IOS_BUILT_IN_TAGS, UVUE_WEB_BUILT_IN_CUSTOM_ELEMENTS, UVUE_WEB_BUILT_IN_TAGS, UniBaseNode, UniCommentNode, UniElement, UniEvent, UniInputElement, UniLifecycleHooks, UniNode, UniTextAreaElement, UniTextNode, VIRTUAL_HOST_CLASS, VIRTUAL_HOST_HIDDEN, VIRTUAL_HOST_ID, VIRTUAL_HOST_STYLE, WEB_INVOKE_APPSERVICE, WXS_MODULES, WXS_PROTOCOL, addFont, addLeadingSlash, borderStyles, cache, cacheStringFunction, callOptions, createIsCustomElement, createRpx2Unit, createUniEvent, customizeEvent, debounce, decode, decodedQuery, defaultMiniProgramRpx2Unit, defaultNVueRpx2Unit, defaultRpx2Unit, dynamicSlotName, forcePatchProp, formatDateTime, formatLog, getCustomDataset, getEnvLocale, getGlobal, getLen, getValueByDataPath, initCustomDatasetOnce, invokeArrayFns, invokeCreateErrorHandler, invokeCreateVueAppHook, isAppHarmonyUVueNativeTag, isAppIOSUVueNativeTag, isAppNVueNativeTag, isAppNativeTag, isAppUVueBuiltInEasyComponent, isAppUVueNativeTag, isAppVoidTag, isBuiltInComponent, isComponentInternalInstance, isComponentTag, isGloballyAllowed, isH5CustomElement, isH5NativeTag, isIntegerKey, isMiniProgramNativeTag, isMiniProgramUVueNativeTag, isRootHook, isRootImmediateHook, isUniLifecycleHook, isUniXElement, normalizeClass, normalizeDataset, normalizeEventType, normalizeProps, normalizeStyle, normalizeStyles, normalizeTabBarStyles, normalizeTarget, normalizeTitleColor, onCreateVueApp, once, parseEventName, parseNVueDataset, parseQuery, parseUrl, passive, plusReady, removeLeadingSlash, resolveComponentInstance, resolveOwnerEl, resolveOwnerVm, sanitise, scrollTo, sortObject, stringifyQuery, updateElementStyle };\n","import { isRootHook, getValueByDataPath, isUniLifecycleHook, ON_ERROR, UniLifecycleHooks, invokeCreateErrorHandler, dynamicSlotName } from '@dcloudio/uni-shared';\nimport { NOOP, extend, isSymbol, isObject, def, hasChanged, isFunction, isArray, isPromise, camelize, capitalize, EMPTY_OBJ, remove, toHandlerKey, hasOwn, hyphenate, isReservedProp, toRawType, isString, normalizeClass, normalizeStyle, isOn, toTypeString, isMap, isIntegerKey, isSet, isPlainObject, makeMap, invokeArrayFns, isBuiltInDirective, looseToNumber, NO, EMPTY_ARR, isModelListener, toNumber, toDisplayString } from '@vue/shared';\nexport { EMPTY_OBJ, camelize, normalizeClass, normalizeProps, normalizeStyle, toDisplayString, toHandlerKey } from '@vue/shared';\n\n/**\n* @dcloudio/uni-mp-vue v3.4.21\n* (c) 2018-present Yuxi (Evan) You and Vue contributors\n* @license MIT\n**/\n\nfunction warn$2(msg, ...args) {\n console.warn(`[Vue warn] ${msg}`, ...args);\n}\n\nlet activeEffectScope;\nclass EffectScope {\n constructor(detached = false) {\n this.detached = detached;\n /**\n * @internal\n */\n this._active = true;\n /**\n * @internal\n */\n this.effects = [];\n /**\n * @internal\n */\n this.cleanups = [];\n this.parent = activeEffectScope;\n if (!detached && activeEffectScope) {\n this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(\n this\n ) - 1;\n }\n }\n get active() {\n return this._active;\n }\n run(fn) {\n if (this._active) {\n const currentEffectScope = activeEffectScope;\n try {\n activeEffectScope = this;\n return fn();\n } finally {\n activeEffectScope = currentEffectScope;\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(`cannot run an inactive effect scope.`);\n }\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n on() {\n activeEffectScope = this;\n }\n /**\n * This should only be called on non-detached scopes\n * @internal\n */\n off() {\n activeEffectScope = this.parent;\n }\n stop(fromParent) {\n if (this._active) {\n let i, l;\n for (i = 0, l = this.effects.length; i < l; i++) {\n this.effects[i].stop();\n }\n for (i = 0, l = this.cleanups.length; i < l; i++) {\n this.cleanups[i]();\n }\n if (this.scopes) {\n for (i = 0, l = this.scopes.length; i < l; i++) {\n this.scopes[i].stop(true);\n }\n }\n if (!this.detached && this.parent && !fromParent) {\n const last = this.parent.scopes.pop();\n if (last && last !== this) {\n this.parent.scopes[this.index] = last;\n last.index = this.index;\n }\n }\n this.parent = void 0;\n this._active = false;\n }\n }\n}\nfunction effectScope(detached) {\n return new EffectScope(detached);\n}\nfunction recordEffectScope(effect, scope = activeEffectScope) {\n if (scope && scope.active) {\n scope.effects.push(effect);\n }\n}\nfunction getCurrentScope() {\n return activeEffectScope;\n}\nfunction onScopeDispose(fn) {\n if (activeEffectScope) {\n activeEffectScope.cleanups.push(fn);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(\n `onScopeDispose() is called when there is no active effect scope to be associated with.`\n );\n }\n}\n\nlet activeEffect;\nclass ReactiveEffect {\n constructor(fn, trigger, scheduler, scope) {\n this.fn = fn;\n this.trigger = trigger;\n this.scheduler = scheduler;\n this.active = true;\n this.deps = [];\n /**\n * @internal\n */\n this._dirtyLevel = 4;\n /**\n * @internal\n */\n this._trackId = 0;\n /**\n * @internal\n */\n this._runnings = 0;\n /**\n * @internal\n */\n this._shouldSchedule = false;\n /**\n * @internal\n */\n this._depsLength = 0;\n recordEffectScope(this, scope);\n }\n get dirty() {\n if (this._dirtyLevel === 2 || this._dirtyLevel === 3) {\n this._dirtyLevel = 1;\n pauseTracking();\n for (let i = 0; i < this._depsLength; i++) {\n const dep = this.deps[i];\n if (dep.computed) {\n triggerComputed(dep.computed);\n if (this._dirtyLevel >= 4) {\n break;\n }\n }\n }\n if (this._dirtyLevel === 1) {\n this._dirtyLevel = 0;\n }\n resetTracking();\n }\n return this._dirtyLevel >= 4;\n }\n set dirty(v) {\n this._dirtyLevel = v ? 4 : 0;\n }\n run() {\n this._dirtyLevel = 0;\n if (!this.active) {\n return this.fn();\n }\n let lastShouldTrack = shouldTrack;\n let lastEffect = activeEffect;\n try {\n shouldTrack = true;\n activeEffect = this;\n this._runnings++;\n preCleanupEffect(this);\n return this.fn();\n } finally {\n postCleanupEffect(this);\n this._runnings--;\n activeEffect = lastEffect;\n shouldTrack = lastShouldTrack;\n }\n }\n stop() {\n var _a;\n if (this.active) {\n preCleanupEffect(this);\n postCleanupEffect(this);\n (_a = this.onStop) == null ? void 0 : _a.call(this);\n this.active = false;\n }\n }\n}\nfunction triggerComputed(computed) {\n return computed.value;\n}\nfunction preCleanupEffect(effect2) {\n effect2._trackId++;\n effect2._depsLength = 0;\n}\nfunction postCleanupEffect(effect2) {\n if (effect2.deps.length > effect2._depsLength) {\n for (let i = effect2._depsLength; i < effect2.deps.length; i++) {\n cleanupDepEffect(effect2.deps[i], effect2);\n }\n effect2.deps.length = effect2._depsLength;\n }\n}\nfunction cleanupDepEffect(dep, effect2) {\n const trackId = dep.get(effect2);\n if (trackId !== void 0 && effect2._trackId !== trackId) {\n dep.delete(effect2);\n if (dep.size === 0) {\n dep.cleanup();\n }\n }\n}\nfunction effect(fn, options) {\n if (fn.effect instanceof ReactiveEffect) {\n fn = fn.effect.fn;\n }\n const _effect = new ReactiveEffect(fn, NOOP, () => {\n if (_effect.dirty) {\n _effect.run();\n }\n });\n if (options) {\n extend(_effect, options);\n if (options.scope)\n recordEffectScope(_effect, options.scope);\n }\n if (!options || !options.lazy) {\n _effect.run();\n }\n const runner = _effect.run.bind(_effect);\n runner.effect = _effect;\n return runner;\n}\nfunction stop(runner) {\n runner.effect.stop();\n}\nlet shouldTrack = true;\nlet pauseScheduleStack = 0;\nconst trackStack = [];\nfunction pauseTracking() {\n trackStack.push(shouldTrack);\n shouldTrack = false;\n}\nfunction resetTracking() {\n const last = trackStack.pop();\n shouldTrack = last === void 0 ? true : last;\n}\nfunction pauseScheduling() {\n pauseScheduleStack++;\n}\nfunction resetScheduling() {\n pauseScheduleStack--;\n while (!pauseScheduleStack && queueEffectSchedulers.length) {\n queueEffectSchedulers.shift()();\n }\n}\nfunction trackEffect(effect2, dep, debuggerEventExtraInfo) {\n var _a;\n if (dep.get(effect2) !== effect2._trackId) {\n dep.set(effect2, effect2._trackId);\n const oldDep = effect2.deps[effect2._depsLength];\n if (oldDep !== dep) {\n if (oldDep) {\n cleanupDepEffect(oldDep, effect2);\n }\n effect2.deps[effect2._depsLength++] = dep;\n } else {\n effect2._depsLength++;\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n (_a = effect2.onTrack) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo));\n }\n }\n}\nconst queueEffectSchedulers = [];\nfunction triggerEffects(dep, dirtyLevel, debuggerEventExtraInfo) {\n var _a;\n pauseScheduling();\n for (const effect2 of dep.keys()) {\n let tracking;\n if (effect2._dirtyLevel < dirtyLevel && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {\n effect2._shouldSchedule || (effect2._shouldSchedule = effect2._dirtyLevel === 0);\n effect2._dirtyLevel = dirtyLevel;\n }\n if (effect2._shouldSchedule && (tracking != null ? tracking : tracking = dep.get(effect2) === effect2._trackId)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n (_a = effect2.onTrigger) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo));\n }\n effect2.trigger();\n if ((!effect2._runnings || effect2.allowRecurse) && effect2._dirtyLevel !== 2) {\n effect2._shouldSchedule = false;\n if (effect2.scheduler) {\n queueEffectSchedulers.push(effect2.scheduler);\n }\n }\n }\n }\n resetScheduling();\n}\n\nconst createDep = (cleanup, computed) => {\n const dep = /* @__PURE__ */ new Map();\n dep.cleanup = cleanup;\n dep.computed = computed;\n return dep;\n};\n\nconst targetMap = /* @__PURE__ */ new WeakMap();\nconst ITERATE_KEY = Symbol(!!(process.env.NODE_ENV !== \"production\") ? \"iterate\" : \"\");\nconst MAP_KEY_ITERATE_KEY = Symbol(!!(process.env.NODE_ENV !== \"production\") ? \"Map key iterate\" : \"\");\nfunction track(target, type, key) {\n if (shouldTrack && activeEffect) {\n let depsMap = targetMap.get(target);\n if (!depsMap) {\n targetMap.set(target, depsMap = /* @__PURE__ */ new Map());\n }\n let dep = depsMap.get(key);\n if (!dep) {\n depsMap.set(key, dep = createDep(() => depsMap.delete(key)));\n }\n trackEffect(\n activeEffect,\n dep,\n !!(process.env.NODE_ENV !== \"production\") ? {\n target,\n type,\n key\n } : void 0\n );\n }\n}\nfunction trigger(target, type, key, newValue, oldValue, oldTarget) {\n const depsMap = targetMap.get(target);\n if (!depsMap) {\n return;\n }\n let deps = [];\n if (type === \"clear\") {\n deps = [...depsMap.values()];\n } else if (key === \"length\" && isArray(target)) {\n const newLength = Number(newValue);\n depsMap.forEach((dep, key2) => {\n if (key2 === \"length\" || !isSymbol(key2) && key2 >= newLength) {\n deps.push(dep);\n }\n });\n } else {\n if (key !== void 0) {\n deps.push(depsMap.get(key));\n }\n switch (type) {\n case \"add\":\n if (!isArray(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n } else if (isIntegerKey(key)) {\n deps.push(depsMap.get(\"length\"));\n }\n break;\n case \"delete\":\n if (!isArray(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n if (isMap(target)) {\n deps.push(depsMap.get(MAP_KEY_ITERATE_KEY));\n }\n }\n break;\n case \"set\":\n if (isMap(target)) {\n deps.push(depsMap.get(ITERATE_KEY));\n }\n break;\n }\n }\n pauseScheduling();\n for (const dep of deps) {\n if (dep) {\n triggerEffects(\n dep,\n 4,\n !!(process.env.NODE_ENV !== \"production\") ? {\n target,\n type,\n key,\n newValue,\n oldValue,\n oldTarget\n } : void 0\n );\n }\n }\n resetScheduling();\n}\nfunction getDepFromReactive(object, key) {\n var _a;\n return (_a = targetMap.get(object)) == null ? void 0 : _a.get(key);\n}\n\nconst isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`);\nconst builtInSymbols = new Set(\n /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((key) => key !== \"arguments\" && key !== \"caller\").map((key) => Symbol[key]).filter(isSymbol)\n);\nconst arrayInstrumentations = /* @__PURE__ */ createArrayInstrumentations();\nfunction createArrayInstrumentations() {\n const instrumentations = {};\n [\"includes\", \"indexOf\", \"lastIndexOf\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n const arr = toRaw(this);\n for (let i = 0, l = this.length; i < l; i++) {\n track(arr, \"get\", i + \"\");\n }\n const res = arr[key](...args);\n if (res === -1 || res === false) {\n return arr[key](...args.map(toRaw));\n } else {\n return res;\n }\n };\n });\n [\"push\", \"pop\", \"shift\", \"unshift\", \"splice\"].forEach((key) => {\n instrumentations[key] = function(...args) {\n pauseTracking();\n pauseScheduling();\n const res = toRaw(this)[key].apply(this, args);\n resetScheduling();\n resetTracking();\n return res;\n };\n });\n return instrumentations;\n}\nfunction hasOwnProperty(key) {\n const obj = toRaw(this);\n track(obj, \"has\", key);\n return obj.hasOwnProperty(key);\n}\nclass BaseReactiveHandler {\n constructor(_isReadonly = false, _isShallow = false) {\n this._isReadonly = _isReadonly;\n this._isShallow = _isShallow;\n }\n get(target, key, receiver) {\n const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow;\n if (key === \"__v_isReactive\") {\n return !isReadonly2;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly2;\n } else if (key === \"__v_isShallow\") {\n return isShallow2;\n } else if (key === \"__v_raw\") {\n if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || // receiver is not the reactive proxy, but has the same prototype\n // this means the reciever is a user proxy of the reactive proxy\n Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {\n return target;\n }\n return;\n }\n const targetIsArray = isArray(target);\n if (!isReadonly2) {\n if (targetIsArray && hasOwn(arrayInstrumentations, key)) {\n return Reflect.get(arrayInstrumentations, key, receiver);\n }\n if (key === \"hasOwnProperty\") {\n return hasOwnProperty;\n }\n }\n const res = Reflect.get(target, key, receiver);\n if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {\n return res;\n }\n if (!isReadonly2) {\n track(target, \"get\", key);\n }\n if (isShallow2) {\n return res;\n }\n if (isRef(res)) {\n return targetIsArray && isIntegerKey(key) ? res : res.value;\n }\n if (isObject(res)) {\n return isReadonly2 ? readonly(res) : reactive(res);\n }\n return res;\n }\n}\nclass MutableReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(false, isShallow2);\n }\n set(target, key, value, receiver) {\n let oldValue = target[key];\n if (!this._isShallow) {\n const isOldValueReadonly = isReadonly(oldValue);\n if (!isShallow(value) && !isReadonly(value)) {\n oldValue = toRaw(oldValue);\n value = toRaw(value);\n }\n if (!isArray(target) && isRef(oldValue) && !isRef(value)) {\n if (isOldValueReadonly) {\n return false;\n } else {\n oldValue.value = value;\n return true;\n }\n }\n }\n const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key);\n const result = Reflect.set(target, key, value, receiver);\n if (target === toRaw(receiver)) {\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n }\n return result;\n }\n deleteProperty(target, key) {\n const hadKey = hasOwn(target, key);\n const oldValue = target[key];\n const result = Reflect.deleteProperty(target, key);\n if (result && hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n }\n has(target, key) {\n const result = Reflect.has(target, key);\n if (!isSymbol(key) || !builtInSymbols.has(key)) {\n track(target, \"has\", key);\n }\n return result;\n }\n ownKeys(target) {\n track(\n target,\n \"iterate\",\n isArray(target) ? \"length\" : ITERATE_KEY\n );\n return Reflect.ownKeys(target);\n }\n}\nclass ReadonlyReactiveHandler extends BaseReactiveHandler {\n constructor(isShallow2 = false) {\n super(true, isShallow2);\n }\n set(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(\n `Set operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n deleteProperty(target, key) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(\n `Delete operation on key \"${String(key)}\" failed: target is readonly.`,\n target\n );\n }\n return true;\n }\n}\nconst mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler();\nconst readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler();\nconst shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(\n true\n);\nconst shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true);\n\nconst toShallow = (value) => value;\nconst getProto = (v) => Reflect.getPrototypeOf(v);\nfunction get(target, key, isReadonly = false, isShallow = false) {\n target = target[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!isReadonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"get\", key);\n }\n track(rawTarget, \"get\", rawKey);\n }\n const { has: has2 } = getProto(rawTarget);\n const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;\n if (has2.call(rawTarget, key)) {\n return wrap(target.get(key));\n } else if (has2.call(rawTarget, rawKey)) {\n return wrap(target.get(rawKey));\n } else if (target !== rawTarget) {\n target.get(key);\n }\n}\nfunction has(key, isReadonly = false) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const rawKey = toRaw(key);\n if (!isReadonly) {\n if (hasChanged(key, rawKey)) {\n track(rawTarget, \"has\", key);\n }\n track(rawTarget, \"has\", rawKey);\n }\n return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey);\n}\nfunction size(target, isReadonly = false) {\n target = target[\"__v_raw\"];\n !isReadonly && track(toRaw(target), \"iterate\", ITERATE_KEY);\n return Reflect.get(target, \"size\", target);\n}\nfunction add(value) {\n value = toRaw(value);\n const target = toRaw(this);\n const proto = getProto(target);\n const hadKey = proto.has.call(target, value);\n if (!hadKey) {\n target.add(value);\n trigger(target, \"add\", value, value);\n }\n return this;\n}\nfunction set$1(key, value) {\n value = toRaw(value);\n const target = toRaw(this);\n const { has: has2, get: get2 } = getProto(target);\n let hadKey = has2.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has2.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has2, key);\n }\n const oldValue = get2.call(target, key);\n target.set(key, value);\n if (!hadKey) {\n trigger(target, \"add\", key, value);\n } else if (hasChanged(value, oldValue)) {\n trigger(target, \"set\", key, value, oldValue);\n }\n return this;\n}\nfunction deleteEntry(key) {\n const target = toRaw(this);\n const { has: has2, get: get2 } = getProto(target);\n let hadKey = has2.call(target, key);\n if (!hadKey) {\n key = toRaw(key);\n hadKey = has2.call(target, key);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n checkIdentityKeys(target, has2, key);\n }\n const oldValue = get2 ? get2.call(target, key) : void 0;\n const result = target.delete(key);\n if (hadKey) {\n trigger(target, \"delete\", key, void 0, oldValue);\n }\n return result;\n}\nfunction clear() {\n const target = toRaw(this);\n const hadItems = target.size !== 0;\n const oldTarget = !!(process.env.NODE_ENV !== \"production\") ? isMap(target) ? new Map(target) : new Set(target) : void 0;\n const result = target.clear();\n if (hadItems) {\n trigger(target, \"clear\", void 0, void 0, oldTarget);\n }\n return result;\n}\nfunction createForEach(isReadonly, isShallow) {\n return function forEach(callback, thisArg) {\n const observed = this;\n const target = observed[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;\n !isReadonly && track(rawTarget, \"iterate\", ITERATE_KEY);\n return target.forEach((value, key) => {\n return callback.call(thisArg, wrap(value), wrap(key), observed);\n });\n };\n}\nfunction createIterableMethod(method, isReadonly, isShallow) {\n return function(...args) {\n const target = this[\"__v_raw\"];\n const rawTarget = toRaw(target);\n const targetIsMap = isMap(rawTarget);\n const isPair = method === \"entries\" || method === Symbol.iterator && targetIsMap;\n const isKeyOnly = method === \"keys\" && targetIsMap;\n const innerIterator = target[method](...args);\n const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive;\n !isReadonly && track(\n rawTarget,\n \"iterate\",\n isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY\n );\n return {\n // iterator protocol\n next() {\n const { value, done } = innerIterator.next();\n return done ? { value, done } : {\n value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),\n done\n };\n },\n // iterable protocol\n [Symbol.iterator]() {\n return this;\n }\n };\n };\n}\nfunction createReadonlyMethod(type) {\n return function(...args) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const key = args[0] ? `on key \"${args[0]}\" ` : ``;\n warn$2(\n `${capitalize(type)} operation ${key}failed: target is readonly.`,\n toRaw(this)\n );\n }\n return type === \"delete\" ? false : type === \"clear\" ? void 0 : this;\n };\n}\nfunction createInstrumentations() {\n const mutableInstrumentations2 = {\n get(key) {\n return get(this, key);\n },\n get size() {\n return size(this);\n },\n has,\n add,\n set: set$1,\n delete: deleteEntry,\n clear,\n forEach: createForEach(false, false)\n };\n const shallowInstrumentations2 = {\n get(key) {\n return get(this, key, false, true);\n },\n get size() {\n return size(this);\n },\n has,\n add,\n set: set$1,\n delete: deleteEntry,\n clear,\n forEach: createForEach(false, true)\n };\n const readonlyInstrumentations2 = {\n get(key) {\n return get(this, key, true);\n },\n get size() {\n return size(this, true);\n },\n has(key) {\n return has.call(this, key, true);\n },\n add: createReadonlyMethod(\"add\"),\n set: createReadonlyMethod(\"set\"),\n delete: createReadonlyMethod(\"delete\"),\n clear: createReadonlyMethod(\"clear\"),\n forEach: createForEach(true, false)\n };\n const shallowReadonlyInstrumentations2 = {\n get(key) {\n return get(this, key, true, true);\n },\n get size() {\n return size(this, true);\n },\n has(key) {\n return has.call(this, key, true);\n },\n add: createReadonlyMethod(\"add\"),\n set: createReadonlyMethod(\"set\"),\n delete: createReadonlyMethod(\"delete\"),\n clear: createReadonlyMethod(\"clear\"),\n forEach: createForEach(true, true)\n };\n const iteratorMethods = [\n \"keys\",\n \"values\",\n \"entries\",\n Symbol.iterator\n ];\n iteratorMethods.forEach((method) => {\n mutableInstrumentations2[method] = createIterableMethod(method, false, false);\n readonlyInstrumentations2[method] = createIterableMethod(method, true, false);\n shallowInstrumentations2[method] = createIterableMethod(method, false, true);\n shallowReadonlyInstrumentations2[method] = createIterableMethod(\n method,\n true,\n true\n );\n });\n return [\n mutableInstrumentations2,\n readonlyInstrumentations2,\n shallowInstrumentations2,\n shallowReadonlyInstrumentations2\n ];\n}\nconst [\n mutableInstrumentations,\n readonlyInstrumentations,\n shallowInstrumentations,\n shallowReadonlyInstrumentations\n] = /* @__PURE__ */ createInstrumentations();\nfunction createInstrumentationGetter(isReadonly, shallow) {\n const instrumentations = shallow ? isReadonly ? shallowReadonlyInstrumentations : shallowInstrumentations : isReadonly ? readonlyInstrumentations : mutableInstrumentations;\n return (target, key, receiver) => {\n if (key === \"__v_isReactive\") {\n return !isReadonly;\n } else if (key === \"__v_isReadonly\") {\n return isReadonly;\n } else if (key === \"__v_raw\") {\n return target;\n }\n return Reflect.get(\n hasOwn(instrumentations, key) && key in target ? instrumentations : target,\n key,\n receiver\n );\n };\n}\nconst mutableCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, false)\n};\nconst shallowCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(false, true)\n};\nconst readonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, false)\n};\nconst shallowReadonlyCollectionHandlers = {\n get: /* @__PURE__ */ createInstrumentationGetter(true, true)\n};\nfunction checkIdentityKeys(target, has2, key) {\n const rawKey = toRaw(key);\n if (rawKey !== key && has2.call(target, rawKey)) {\n const type = toRawType(target);\n warn$2(\n `Reactive ${type} contains both the raw and reactive versions of the same object${type === `Map` ? ` as keys` : ``}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.`\n );\n }\n}\n\nconst reactiveMap = /* @__PURE__ */ new WeakMap();\nconst shallowReactiveMap = /* @__PURE__ */ new WeakMap();\nconst readonlyMap = /* @__PURE__ */ new WeakMap();\nconst shallowReadonlyMap = /* @__PURE__ */ new WeakMap();\nfunction targetTypeMap(rawType) {\n switch (rawType) {\n case \"Object\":\n case \"Array\":\n return 1 /* COMMON */;\n case \"Map\":\n case \"Set\":\n case \"WeakMap\":\n case \"WeakSet\":\n return 2 /* COLLECTION */;\n default:\n return 0 /* INVALID */;\n }\n}\nfunction getTargetType(value) {\n return value[\"__v_skip\"] || !Object.isExtensible(value) ? 0 /* INVALID */ : targetTypeMap(toRawType(value));\n}\nfunction reactive(target) {\n if (isReadonly(target)) {\n return target;\n }\n return createReactiveObject(\n target,\n false,\n mutableHandlers,\n mutableCollectionHandlers,\n reactiveMap\n );\n}\nfunction shallowReactive(target) {\n return createReactiveObject(\n target,\n false,\n shallowReactiveHandlers,\n shallowCollectionHandlers,\n shallowReactiveMap\n );\n}\nfunction readonly(target) {\n return createReactiveObject(\n target,\n true,\n readonlyHandlers,\n readonlyCollectionHandlers,\n readonlyMap\n );\n}\nfunction shallowReadonly(target) {\n return createReactiveObject(\n target,\n true,\n shallowReadonlyHandlers,\n shallowReadonlyCollectionHandlers,\n shallowReadonlyMap\n );\n}\nfunction createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) {\n if (!isObject(target)) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$2(`value cannot be made reactive: ${String(target)}`);\n }\n return target;\n }\n if (target[\"__v_raw\"] && !(isReadonly2 && target[\"__v_isReactive\"])) {\n return target;\n }\n const existingProxy = proxyMap.get(target);\n if (existingProxy) {\n return existingProxy;\n }\n const targetType = getTargetType(target);\n if (targetType === 0 /* INVALID */) {\n return target;\n }\n const proxy = new Proxy(\n target,\n targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers\n );\n proxyMap.set(target, proxy);\n return proxy;\n}\nfunction isReactive(value) {\n if (isReadonly(value)) {\n return isReactive(value[\"__v_raw\"]);\n }\n return !!(value && value[\"__v_isReactive\"]);\n}\nfunction isReadonly(value) {\n return !!(value && value[\"__v_isReadonly\"]);\n}\nfunction isShallow(value) {\n return !!(value && value[\"__v_isShallow\"]);\n}\nfunction isProxy(value) {\n return isReactive(value) || isReadonly(value);\n}\nfunction toRaw(observed) {\n const raw = observed && observed[\"__v_raw\"];\n return raw ? toRaw(raw) : observed;\n}\nfunction markRaw(value) {\n if (Object.isExtensible(value)) {\n def(value, \"__v_skip\", true);\n }\n return value;\n}\nconst toReactive = (value) => isObject(value) ? reactive(value) : value;\nconst toReadonly = (value) => isObject(value) ? readonly(value) : value;\n\nconst COMPUTED_SIDE_EFFECT_WARN = `Computed is still dirty after getter evaluation, likely because a computed is mutating its own dependency in its getter. State mutations in computed getters should be avoided. Check the docs for more details: https://vuejs.org/guide/essentials/computed.html#getters-should-be-side-effect-free`;\nclass ComputedRefImpl {\n constructor(getter, _setter, isReadonly, isSSR) {\n this.getter = getter;\n this._setter = _setter;\n this.dep = void 0;\n this.__v_isRef = true;\n this[\"__v_isReadonly\"] = false;\n this.effect = new ReactiveEffect(\n () => getter(this._value),\n () => triggerRefValue(\n this,\n this.effect._dirtyLevel === 2 ? 2 : 3\n )\n );\n this.effect.computed = this;\n this.effect.active = this._cacheable = !isSSR;\n this[\"__v_isReadonly\"] = isReadonly;\n }\n get value() {\n const self = toRaw(this);\n if ((!self._cacheable || self.effect.dirty) && hasChanged(self._value, self._value = self.effect.run())) {\n triggerRefValue(self, 4);\n }\n trackRefValue(self);\n if (self.effect._dirtyLevel >= 2) {\n if (!!(process.env.NODE_ENV !== \"production\") && this._warnRecursive) {\n warn$2(COMPUTED_SIDE_EFFECT_WARN, `\n\ngetter: `, this.getter);\n }\n triggerRefValue(self, 2);\n }\n return self._value;\n }\n set value(newValue) {\n this._setter(newValue);\n }\n // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x\n get _dirty() {\n return this.effect.dirty;\n }\n set _dirty(v) {\n this.effect.dirty = v;\n }\n // #endregion\n}\nfunction computed$1(getterOrOptions, debugOptions, isSSR = false) {\n let getter;\n let setter;\n const onlyGetter = isFunction(getterOrOptions);\n if (onlyGetter) {\n getter = getterOrOptions;\n setter = !!(process.env.NODE_ENV !== \"production\") ? () => {\n warn$2(\"Write operation failed: computed value is readonly\");\n } : NOOP;\n } else {\n getter = getterOrOptions.get;\n setter = getterOrOptions.set;\n }\n const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR);\n if (!!(process.env.NODE_ENV !== \"production\") && debugOptions && !isSSR) {\n cRef.effect.onTrack = debugOptions.onTrack;\n cRef.effect.onTrigger = debugOptions.onTrigger;\n }\n return cRef;\n}\n\nfunction trackRefValue(ref2) {\n var _a;\n if (shouldTrack && activeEffect) {\n ref2 = toRaw(ref2);\n trackEffect(\n activeEffect,\n (_a = ref2.dep) != null ? _a : ref2.dep = createDep(\n () => ref2.dep = void 0,\n ref2 instanceof ComputedRefImpl ? ref2 : void 0\n ),\n !!(process.env.NODE_ENV !== \"production\") ? {\n target: ref2,\n type: \"get\",\n key: \"value\"\n } : void 0\n );\n }\n}\nfunction triggerRefValue(ref2, dirtyLevel = 4, newVal) {\n ref2 = toRaw(ref2);\n const dep = ref2.dep;\n if (dep) {\n triggerEffects(\n dep,\n dirtyLevel,\n !!(process.env.NODE_ENV !== \"production\") ? {\n target: ref2,\n type: \"set\",\n key: \"value\",\n newValue: newVal\n } : void 0\n );\n }\n}\nfunction isRef(r) {\n return !!(r && r.__v_isRef === true);\n}\nfunction ref(value) {\n return createRef(value, false);\n}\nfunction shallowRef(value) {\n return createRef(value, true);\n}\nfunction createRef(rawValue, shallow) {\n if (isRef(rawValue)) {\n return rawValue;\n }\n return new RefImpl(rawValue, shallow);\n}\nclass RefImpl {\n constructor(value, __v_isShallow) {\n this.__v_isShallow = __v_isShallow;\n this.dep = void 0;\n this.__v_isRef = true;\n this._rawValue = __v_isShallow ? value : toRaw(value);\n this._value = __v_isShallow ? value : toReactive(value);\n }\n get value() {\n trackRefValue(this);\n return this._value;\n }\n set value(newVal) {\n const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal);\n newVal = useDirectValue ? newVal : toRaw(newVal);\n if (hasChanged(newVal, this._rawValue)) {\n this._rawValue = newVal;\n this._value = useDirectValue ? newVal : toReactive(newVal);\n triggerRefValue(this, 4, newVal);\n }\n }\n}\nfunction triggerRef(ref2) {\n triggerRefValue(ref2, 4, !!(process.env.NODE_ENV !== \"production\") ? ref2.value : void 0);\n}\nfunction unref(ref2) {\n return isRef(ref2) ? ref2.value : ref2;\n}\nfunction toValue(source) {\n return isFunction(source) ? source() : unref(source);\n}\nconst shallowUnwrapHandlers = {\n get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)),\n set: (target, key, value, receiver) => {\n const oldValue = target[key];\n if (isRef(oldValue) && !isRef(value)) {\n oldValue.value = value;\n return true;\n } else {\n return Reflect.set(target, key, value, receiver);\n }\n }\n};\nfunction proxyRefs(objectWithRefs) {\n return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers);\n}\nclass CustomRefImpl {\n constructor(factory) {\n this.dep = void 0;\n this.__v_isRef = true;\n const { get, set } = factory(\n () => trackRefValue(this),\n () => triggerRefValue(this)\n );\n this._get = get;\n this._set = set;\n }\n get value() {\n return this._get();\n }\n set value(newVal) {\n this._set(newVal);\n }\n}\nfunction customRef(factory) {\n return new CustomRefImpl(factory);\n}\nfunction toRefs(object) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isProxy(object)) {\n warn$2(`toRefs() expects a reactive object but received a plain one.`);\n }\n const ret = isArray(object) ? new Array(object.length) : {};\n for (const key in object) {\n ret[key] = propertyToRef(object, key);\n }\n return ret;\n}\nclass ObjectRefImpl {\n constructor(_object, _key, _defaultValue) {\n this._object = _object;\n this._key = _key;\n this._defaultValue = _defaultValue;\n this.__v_isRef = true;\n }\n get value() {\n const val = this._object[this._key];\n return val === void 0 ? this._defaultValue : val;\n }\n set value(newVal) {\n this._object[this._key] = newVal;\n }\n get dep() {\n return getDepFromReactive(toRaw(this._object), this._key);\n }\n}\nclass GetterRefImpl {\n constructor(_getter) {\n this._getter = _getter;\n this.__v_isRef = true;\n this.__v_isReadonly = true;\n }\n get value() {\n return this._getter();\n }\n}\nfunction toRef(source, key, defaultValue) {\n if (isRef(source)) {\n return source;\n } else if (isFunction(source)) {\n return new GetterRefImpl(source);\n } else if (isObject(source) && arguments.length > 1) {\n return propertyToRef(source, key, defaultValue);\n } else {\n return ref(source);\n }\n}\nfunction propertyToRef(source, key, defaultValue) {\n const val = source[key];\n return isRef(val) ? val : new ObjectRefImpl(source, key, defaultValue);\n}\n\nconst stack = [];\nfunction pushWarningContext(vnode) {\n stack.push(vnode);\n}\nfunction popWarningContext() {\n stack.pop();\n}\nfunction warn$1(msg, ...args) {\n pauseTracking();\n const instance = stack.length ? stack[stack.length - 1].component : null;\n const appWarnHandler = instance && instance.appContext.config.warnHandler;\n const trace = getComponentTrace();\n if (appWarnHandler) {\n callWithErrorHandling(\n appWarnHandler,\n instance,\n 11,\n [\n msg + args.map((a) => {\n var _a, _b;\n return (_b = (_a = a.toString) == null ? void 0 : _a.call(a)) != null ? _b : JSON.stringify(a);\n }).join(\"\"),\n instance && instance.proxy,\n trace.map(\n ({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>`\n ).join(\"\\n\"),\n trace\n ]\n );\n } else {\n const warnArgs = [`[Vue warn]: ${msg}`, ...args];\n if (trace.length && // avoid spamming console during tests\n true) {\n warnArgs.push(`\n`, ...formatTrace(trace));\n }\n console.warn(...warnArgs);\n }\n resetTracking();\n}\nfunction getComponentTrace() {\n let currentVNode = stack[stack.length - 1];\n if (!currentVNode) {\n return [];\n }\n const normalizedStack = [];\n while (currentVNode) {\n const last = normalizedStack[0];\n if (last && last.vnode === currentVNode) {\n last.recurseCount++;\n } else {\n normalizedStack.push({\n vnode: currentVNode,\n recurseCount: 0\n });\n }\n const parentInstance = currentVNode.component && currentVNode.component.parent;\n currentVNode = parentInstance && parentInstance.vnode;\n }\n return normalizedStack;\n}\nfunction formatTrace(trace) {\n const logs = [];\n trace.forEach((entry, i) => {\n logs.push(...i === 0 ? [] : [`\n`], ...formatTraceEntry(entry));\n });\n return logs;\n}\nfunction formatTraceEntry({ vnode, recurseCount }) {\n const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``;\n const isRoot = vnode.component ? vnode.component.parent == null : false;\n const open = ` at <${formatComponentName(\n vnode.component,\n vnode.type,\n isRoot\n )}`;\n const close = `>` + postfix;\n return vnode.props ? [open, ...formatProps(vnode.props), close] : [open + close];\n}\nfunction formatProps(props) {\n const res = [];\n const keys = Object.keys(props);\n keys.slice(0, 3).forEach((key) => {\n res.push(...formatProp(key, props[key]));\n });\n if (keys.length > 3) {\n res.push(` ...`);\n }\n return res;\n}\nfunction formatProp(key, value, raw) {\n if (isString(value)) {\n value = JSON.stringify(value);\n return raw ? value : [`${key}=${value}`];\n } else if (typeof value === \"number\" || typeof value === \"boolean\" || value == null) {\n return raw ? value : [`${key}=${value}`];\n } else if (isRef(value)) {\n value = formatProp(key, toRaw(value.value), true);\n return raw ? value : [`${key}=Ref<`, value, `>`];\n } else if (isFunction(value)) {\n return [`${key}=fn${value.name ? `<${value.name}>` : ``}`];\n } else {\n value = toRaw(value);\n return raw ? value : [`${key}=`, value];\n }\n}\n\nconst ErrorTypeStrings = {\n [\"sp\"]: \"serverPrefetch hook\",\n [\"bc\"]: \"beforeCreate hook\",\n [\"c\"]: \"created hook\",\n [\"bm\"]: \"beforeMount hook\",\n [\"m\"]: \"mounted hook\",\n [\"bu\"]: \"beforeUpdate hook\",\n [\"u\"]: \"updated\",\n [\"bum\"]: \"beforeUnmount hook\",\n [\"um\"]: \"unmounted hook\",\n [\"a\"]: \"activated hook\",\n [\"da\"]: \"deactivated hook\",\n [\"ec\"]: \"errorCaptured hook\",\n [\"rtc\"]: \"renderTracked hook\",\n [\"rtg\"]: \"renderTriggered hook\",\n [0]: \"setup function\",\n [1]: \"render function\",\n [2]: \"watcher getter\",\n [3]: \"watcher callback\",\n [4]: \"watcher cleanup function\",\n [5]: \"native event handler\",\n [6]: \"component event handler\",\n [7]: \"vnode hook\",\n [8]: \"directive hook\",\n [9]: \"transition hook\",\n [10]: \"app errorHandler\",\n [11]: \"app warnHandler\",\n [12]: \"ref function\",\n [13]: \"async component loader\",\n [14]: \"scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core .\"\n};\nfunction callWithErrorHandling(fn, instance, type, args) {\n try {\n return args ? fn(...args) : fn();\n } catch (err) {\n handleError(err, instance, type);\n }\n}\nfunction callWithAsyncErrorHandling(fn, instance, type, args) {\n if (isFunction(fn)) {\n const res = callWithErrorHandling(fn, instance, type, args);\n if (res && isPromise(res)) {\n res.catch((err) => {\n handleError(err, instance, type);\n });\n }\n return res;\n }\n const values = [];\n for (let i = 0; i < fn.length; i++) {\n values.push(callWithAsyncErrorHandling(fn[i], instance, type, args));\n }\n return values;\n}\nfunction handleError(err, instance, type, throwInDev = true) {\n const contextVNode = instance ? instance.vnode : null;\n if (instance) {\n let cur = instance.parent;\n const exposedInstance = instance.proxy;\n const errorInfo = !!(process.env.NODE_ENV !== \"production\") ? ErrorTypeStrings[type] || type : `https://vuejs.org/error-reference/#runtime-${type}`;\n while (cur) {\n const errorCapturedHooks = cur.ec;\n if (errorCapturedHooks) {\n for (let i = 0; i < errorCapturedHooks.length; i++) {\n if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) {\n return;\n }\n }\n }\n cur = cur.parent;\n }\n const appErrorHandler = instance.appContext.config.errorHandler;\n if (appErrorHandler) {\n callWithErrorHandling(\n appErrorHandler,\n null,\n 10,\n [err, exposedInstance, errorInfo]\n );\n return;\n }\n }\n logError(err, type, contextVNode, throwInDev);\n}\nfunction logError(err, type, contextVNode, throwInDev = true) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const info = ErrorTypeStrings[type] || type;\n if (contextVNode) {\n pushWarningContext(contextVNode);\n }\n warn$1(`Unhandled error${info ? ` during execution of ${info}` : ``}`);\n if (contextVNode) {\n popWarningContext();\n }\n if (throwInDev) {\n console.error(err);\n } else {\n console.error(err);\n }\n } else {\n console.error(err);\n }\n}\n\nlet isFlushing = false;\nlet isFlushPending = false;\nconst queue = [];\nlet flushIndex = 0;\nconst pendingPostFlushCbs = [];\nlet activePostFlushCbs = null;\nlet postFlushIndex = 0;\nconst resolvedPromise = /* @__PURE__ */ Promise.resolve();\nlet currentFlushPromise = null;\nconst RECURSION_LIMIT = 100;\nfunction nextTick$1(fn) {\n const p = currentFlushPromise || resolvedPromise;\n return fn ? p.then(this ? fn.bind(this) : fn) : p;\n}\nfunction findInsertionIndex(id) {\n let start = flushIndex + 1;\n let end = queue.length;\n while (start < end) {\n const middle = start + end >>> 1;\n const middleJob = queue[middle];\n const middleJobId = getId(middleJob);\n if (middleJobId < id || middleJobId === id && middleJob.pre) {\n start = middle + 1;\n } else {\n end = middle;\n }\n }\n return start;\n}\nfunction queueJob(job) {\n if (!queue.length || !queue.includes(\n job,\n isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex\n )) {\n if (job.id == null) {\n queue.push(job);\n } else {\n queue.splice(findInsertionIndex(job.id), 0, job);\n }\n queueFlush();\n }\n}\nfunction queueFlush() {\n if (!isFlushing && !isFlushPending) {\n isFlushPending = true;\n currentFlushPromise = resolvedPromise.then(flushJobs);\n }\n}\nfunction hasQueueJob(job) {\n return queue.indexOf(job) > -1;\n}\nfunction invalidateJob(job) {\n const i = queue.indexOf(job);\n if (i > flushIndex) {\n queue.splice(i, 1);\n }\n}\nfunction queuePostFlushCb(cb) {\n if (!isArray(cb)) {\n if (!activePostFlushCbs || !activePostFlushCbs.includes(\n cb,\n cb.allowRecurse ? postFlushIndex + 1 : postFlushIndex\n )) {\n pendingPostFlushCbs.push(cb);\n }\n } else {\n pendingPostFlushCbs.push(...cb);\n }\n queueFlush();\n}\nfunction flushPreFlushCbs(instance, seen, i = isFlushing ? flushIndex + 1 : 0) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n for (; i < queue.length; i++) {\n const cb = queue[i];\n if (cb && cb.pre) {\n if (!!(process.env.NODE_ENV !== \"production\") && checkRecursiveUpdates(seen, cb)) {\n continue;\n }\n queue.splice(i, 1);\n i--;\n cb();\n }\n }\n}\nfunction flushPostFlushCbs(seen) {\n if (pendingPostFlushCbs.length) {\n const deduped = [...new Set(pendingPostFlushCbs)].sort(\n (a, b) => getId(a) - getId(b)\n );\n pendingPostFlushCbs.length = 0;\n if (activePostFlushCbs) {\n activePostFlushCbs.push(...deduped);\n return;\n }\n activePostFlushCbs = deduped;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) {\n if (!!(process.env.NODE_ENV !== \"production\") && checkRecursiveUpdates(seen, activePostFlushCbs[postFlushIndex])) {\n continue;\n }\n activePostFlushCbs[postFlushIndex]();\n }\n activePostFlushCbs = null;\n postFlushIndex = 0;\n }\n}\nconst getId = (job) => job.id == null ? Infinity : job.id;\nconst comparator = (a, b) => {\n const diff = getId(a) - getId(b);\n if (diff === 0) {\n if (a.pre && !b.pre)\n return -1;\n if (b.pre && !a.pre)\n return 1;\n }\n return diff;\n};\nfunction flushJobs(seen) {\n isFlushPending = false;\n isFlushing = true;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n seen = seen || /* @__PURE__ */ new Map();\n }\n queue.sort(comparator);\n const check = !!(process.env.NODE_ENV !== \"production\") ? (job) => checkRecursiveUpdates(seen, job) : NOOP;\n try {\n for (flushIndex = 0; flushIndex < queue.length; flushIndex++) {\n const job = queue[flushIndex];\n if (job && job.active !== false) {\n if (!!(process.env.NODE_ENV !== \"production\") && check(job)) {\n continue;\n }\n callWithErrorHandling(job, null, 14);\n }\n }\n } finally {\n flushIndex = 0;\n queue.length = 0;\n flushPostFlushCbs(seen);\n isFlushing = false;\n currentFlushPromise = null;\n if (queue.length || pendingPostFlushCbs.length) {\n flushJobs(seen);\n }\n }\n}\nfunction checkRecursiveUpdates(seen, fn) {\n if (!seen.has(fn)) {\n seen.set(fn, 1);\n } else {\n const count = seen.get(fn);\n if (count > RECURSION_LIMIT) {\n const instance = fn.ownerInstance;\n const componentName = instance && getComponentName(instance.type);\n handleError(\n `Maximum recursive updates exceeded${componentName ? ` in component <${componentName}>` : ``}. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.`,\n null,\n 10\n );\n return true;\n } else {\n seen.set(fn, count + 1);\n }\n }\n}\n\nlet devtools;\nlet buffer = [];\nlet devtoolsNotInstalled = false;\nfunction emit$1(event, ...args) {\n if (devtools) {\n devtools.emit(event, ...args);\n } else if (!devtoolsNotInstalled) {\n buffer.push({ event, args });\n }\n}\nfunction setDevtoolsHook(hook, target) {\n var _a, _b;\n devtools = hook;\n if (devtools) {\n devtools.enabled = true;\n buffer.forEach(({ event, args }) => devtools.emit(event, ...args));\n buffer = [];\n } else if (\n // handle late devtools injection - only do this if we are in an actual\n // browser environment to avoid the timer handle stalling test runner exit\n // (#4815)\n typeof window !== \"undefined\" && // some envs mock window but not fully\n window.HTMLElement && // also exclude jsdom\n !((_b = (_a = window.navigator) == null ? void 0 : _a.userAgent) == null ? void 0 : _b.includes(\"jsdom\"))\n ) {\n const replay = target.__VUE_DEVTOOLS_HOOK_REPLAY__ = target.__VUE_DEVTOOLS_HOOK_REPLAY__ || [];\n replay.push((newHook) => {\n setDevtoolsHook(newHook, target);\n });\n setTimeout(() => {\n if (!devtools) {\n target.__VUE_DEVTOOLS_HOOK_REPLAY__ = null;\n devtoolsNotInstalled = true;\n buffer = [];\n }\n }, 3e3);\n } else {\n devtoolsNotInstalled = true;\n buffer = [];\n }\n}\nfunction devtoolsInitApp(app, version) {\n emit$1(\"app:init\" /* APP_INIT */, app, version, {\n Fragment,\n Text,\n Comment,\n Static\n });\n}\nconst devtoolsComponentAdded = /* @__PURE__ */ createDevtoolsComponentHook(\n \"component:added\" /* COMPONENT_ADDED */\n);\nconst devtoolsComponentUpdated = /* @__PURE__ */ createDevtoolsComponentHook(\"component:updated\" /* COMPONENT_UPDATED */);\nconst _devtoolsComponentRemoved = /* @__PURE__ */ createDevtoolsComponentHook(\n \"component:removed\" /* COMPONENT_REMOVED */\n);\nconst devtoolsComponentRemoved = (component) => {\n if (devtools && typeof devtools.cleanupBuffer === \"function\" && // remove the component if it wasn't buffered\n !devtools.cleanupBuffer(component)) {\n _devtoolsComponentRemoved(component);\n }\n};\n/*! #__NO_SIDE_EFFECTS__ */\n// @__NO_SIDE_EFFECTS__\nfunction createDevtoolsComponentHook(hook) {\n return (component) => {\n emit$1(\n hook,\n component.appContext.app,\n component.uid,\n // fixed by xxxxxx\n // 为 0 是 App,无 parent 是 Page 指向 App\n component.uid === 0 ? void 0 : component.parent ? component.parent.uid : 0,\n component\n );\n };\n}\nconst devtoolsPerfStart = /* @__PURE__ */ createDevtoolsPerformanceHook(\n \"perf:start\" /* PERFORMANCE_START */\n);\nconst devtoolsPerfEnd = /* @__PURE__ */ createDevtoolsPerformanceHook(\n \"perf:end\" /* PERFORMANCE_END */\n);\nfunction createDevtoolsPerformanceHook(hook) {\n return (component, type, time) => {\n emit$1(hook, component.appContext.app, component.uid, component, type, time);\n };\n}\nfunction devtoolsComponentEmit(component, event, params) {\n emit$1(\n \"component:emit\" /* COMPONENT_EMIT */,\n component.appContext.app,\n component,\n event,\n params\n );\n}\n\nfunction emit(instance, event, ...rawArgs) {\n if (instance.isUnmounted)\n return;\n const props = instance.vnode.props || EMPTY_OBJ;\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const {\n emitsOptions,\n propsOptions: [propsOptions]\n } = instance;\n if (emitsOptions) {\n if (!(event in emitsOptions) && true) {\n if (!propsOptions || !(toHandlerKey(event) in propsOptions)) {\n warn$1(\n `Component emitted event \"${event}\" but it is neither declared in the emits option nor as an \"${toHandlerKey(event)}\" prop.`\n );\n }\n } else {\n const validator = emitsOptions[event];\n if (isFunction(validator)) {\n const isValid = validator(...rawArgs);\n if (!isValid) {\n warn$1(\n `Invalid event arguments: event validation failed for event \"${event}\".`\n );\n }\n }\n }\n }\n }\n let args = rawArgs;\n const isModelListener = event.startsWith(\"update:\");\n const modelArg = isModelListener && event.slice(7);\n if (modelArg && modelArg in props) {\n const modifiersKey = `${modelArg === \"modelValue\" ? \"model\" : modelArg}Modifiers`;\n const { number, trim } = props[modifiersKey] || EMPTY_OBJ;\n if (trim) {\n args = rawArgs.map((a) => isString(a) ? a.trim() : a);\n }\n if (number) {\n args = rawArgs.map(looseToNumber);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentEmit(instance, event, args);\n }\n if (!!(process.env.NODE_ENV !== \"production\")) {\n const lowerCaseEvent = event.toLowerCase();\n if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) {\n warn$1(\n `Event \"${lowerCaseEvent}\" is emitted in component ${formatComponentName(\n instance,\n instance.type\n )} but the handler is registered for \"${event}\". Note that HTML attributes are case-insensitive and you cannot use v-on to listen to camelCase events when using in-DOM templates. You should probably use \"${hyphenate(\n event\n )}\" instead of \"${event}\".`\n );\n }\n }\n let handlerName;\n let handler = props[handlerName = toHandlerKey(event)] || // also try camelCase event handler (#2249)\n props[handlerName = toHandlerKey(camelize(event))];\n if (!handler && isModelListener) {\n handler = props[handlerName = toHandlerKey(hyphenate(event))];\n }\n if (handler) {\n callWithAsyncErrorHandling(\n handler,\n instance,\n 6,\n args\n );\n }\n const onceHandler = props[handlerName + `Once`];\n if (onceHandler) {\n if (!instance.emitted) {\n instance.emitted = {};\n } else if (instance.emitted[handlerName]) {\n return;\n }\n instance.emitted[handlerName] = true;\n callWithAsyncErrorHandling(\n onceHandler,\n instance,\n 6,\n args\n );\n }\n}\nfunction normalizeEmitsOptions(comp, appContext, asMixin = false) {\n const cache = appContext.emitsCache;\n const cached = cache.get(comp);\n if (cached !== void 0) {\n return cached;\n }\n const raw = comp.emits;\n let normalized = {};\n let hasExtends = false;\n if (__VUE_OPTIONS_API__ && !isFunction(comp)) {\n const extendEmits = (raw2) => {\n const normalizedFromExtend = normalizeEmitsOptions(raw2, appContext, true);\n if (normalizedFromExtend) {\n hasExtends = true;\n extend(normalized, normalizedFromExtend);\n }\n };\n if (!asMixin && appContext.mixins.length) {\n appContext.mixins.forEach(extendEmits);\n }\n if (comp.extends) {\n extendEmits(comp.extends);\n }\n if (comp.mixins) {\n comp.mixins.forEach(extendEmits);\n }\n }\n if (!raw && !hasExtends) {\n if (isObject(comp)) {\n cache.set(comp, null);\n }\n return null;\n }\n if (isArray(raw)) {\n raw.forEach((key) => normalized[key] = null);\n } else {\n extend(normalized, raw);\n }\n if (isObject(comp)) {\n cache.set(comp, normalized);\n }\n return normalized;\n}\nfunction isEmitListener(options, key) {\n if (!options || !isOn(key)) {\n return false;\n }\n key = key.slice(2).replace(/Once$/, \"\");\n return hasOwn(options, key[0].toLowerCase() + key.slice(1)) || hasOwn(options, hyphenate(key)) || hasOwn(options, key);\n}\n\nlet currentRenderingInstance = null;\nlet currentScopeId = null;\nfunction setCurrentRenderingInstance(instance) {\n const prev = currentRenderingInstance;\n currentRenderingInstance = instance;\n currentScopeId = instance && instance.type.__scopeId || null;\n return prev;\n}\nconst withScopeId = (_id) => withCtx;\nfunction withCtx(fn, ctx = currentRenderingInstance, isNonScopedSlot) {\n if (!ctx)\n return fn;\n if (fn._n) {\n return fn;\n }\n const renderFnWithContext = (...args) => {\n if (renderFnWithContext._d) {\n setBlockTracking(-1);\n }\n const prevInstance = setCurrentRenderingInstance(ctx);\n let res;\n try {\n res = fn(...args);\n } finally {\n setCurrentRenderingInstance(prevInstance);\n if (renderFnWithContext._d) {\n setBlockTracking(1);\n }\n }\n if (!!(process.env.NODE_ENV !== \"production\") || __VUE_PROD_DEVTOOLS__) {\n devtoolsComponentUpdated(ctx);\n }\n return res;\n };\n renderFnWithContext._n = true;\n renderFnWithContext._c = true;\n renderFnWithContext._d = true;\n return renderFnWithContext;\n}\n\nfunction markAttrsAccessed() {\n}\n\nconst COMPONENTS = \"components\";\nconst DIRECTIVES = \"directives\";\nfunction resolveComponent(name, maybeSelfReference) {\n return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name;\n}\nconst NULL_DYNAMIC_COMPONENT = Symbol.for(\"v-ndc\");\nfunction resolveDirective(name) {\n return resolveAsset(DIRECTIVES, name);\n}\nfunction resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) {\n const instance = currentRenderingInstance || currentInstance;\n if (instance) {\n const Component = instance.type;\n if (type === COMPONENTS) {\n const selfName = getComponentName(\n Component,\n false\n );\n if (selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name)))) {\n return Component;\n }\n }\n const res = (\n // local registration\n // check instance[type] first which is resolved for options API\n resolve(instance[type] || Component[type], name) || // global registration\n resolve(instance.appContext[type], name)\n );\n if (!res && maybeSelfReference) {\n return Component;\n }\n if (!!(process.env.NODE_ENV !== \"production\") && warnMissing && !res) {\n const extra = type === COMPONENTS ? `\nIf this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.` : ``;\n warn$1(`Failed to resolve ${type.slice(0, -1)}: ${name}${extra}`);\n }\n return res;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `resolve${capitalize(type.slice(0, -1))} can only be used in render() or setup().`\n );\n }\n}\nfunction resolve(registry, name) {\n return registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]);\n}\n\nconst ssrContextKey = Symbol.for(\"v-scx\");\nconst useSSRContext = () => {\n {\n const ctx = inject(ssrContextKey);\n if (!ctx) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(\n `Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.`\n );\n }\n return ctx;\n }\n};\n\nfunction watchEffect(effect, options) {\n return doWatch(effect, null, options);\n}\nfunction watchPostEffect(effect, options) {\n return doWatch(\n effect,\n null,\n !!(process.env.NODE_ENV !== \"production\") ? extend({}, options, { flush: \"post\" }) : { flush: \"post\" }\n );\n}\nfunction watchSyncEffect(effect, options) {\n return doWatch(\n effect,\n null,\n !!(process.env.NODE_ENV !== \"production\") ? extend({}, options, { flush: \"sync\" }) : { flush: \"sync\" }\n );\n}\nconst INITIAL_WATCHER_VALUE = {};\nfunction watch(source, cb, options) {\n if (!!(process.env.NODE_ENV !== \"production\") && !isFunction(cb)) {\n warn$1(\n `\\`watch(fn, options?)\\` signature has been moved to a separate API. Use \\`watchEffect(fn, options?)\\` instead. \\`watch\\` now only supports \\`watch(source, cb, options?) signature.`\n );\n }\n return doWatch(source, cb, options);\n}\nfunction doWatch(source, cb, {\n immediate,\n deep,\n flush,\n once,\n onTrack,\n onTrigger\n} = EMPTY_OBJ) {\n if (cb && once) {\n const _cb = cb;\n cb = (...args) => {\n _cb(...args);\n unwatch();\n };\n }\n if (!!(process.env.NODE_ENV !== \"production\") && deep !== void 0 && typeof deep === \"number\") {\n warn$1(\n `watch() \"deep\" option with number value will be used as watch depth in future versions. Please use a boolean instead to avoid potential breakage.`\n );\n }\n if (!!(process.env.NODE_ENV !== \"production\") && !cb) {\n if (immediate !== void 0) {\n warn$1(\n `watch() \"immediate\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n if (deep !== void 0) {\n warn$1(\n `watch() \"deep\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n if (once !== void 0) {\n warn$1(\n `watch() \"once\" option is only respected when using the watch(source, callback, options?) signature.`\n );\n }\n }\n const warnInvalidSource = (s) => {\n warn$1(\n `Invalid watch source: `,\n s,\n `A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.`\n );\n };\n const instance = currentInstance;\n const reactiveGetter = (source2) => deep === true ? source2 : (\n // for deep: false, only traverse root-level properties\n traverse(source2, deep === false ? 1 : void 0)\n );\n let getter;\n let forceTrigger = false;\n let isMultiSource = false;\n if (isRef(source)) {\n getter = () => source.value;\n forceTrigger = isShallow(source);\n } else if (isReactive(source)) {\n getter = () => reactiveGetter(source);\n forceTrigger = true;\n } else if (isArray(source)) {\n isMultiSource = true;\n forceTrigger = source.some((s) => isReactive(s) || isShallow(s));\n getter = () => source.map((s) => {\n if (isRef(s)) {\n return s.value;\n } else if (isReactive(s)) {\n return reactiveGetter(s);\n } else if (isFunction(s)) {\n return callWithErrorHandling(s, instance, 2);\n } else {\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(s);\n }\n });\n } else if (isFunction(source)) {\n if (cb) {\n getter = () => callWithErrorHandling(source, instance, 2);\n } else {\n getter = () => {\n if (cleanup) {\n cleanup();\n }\n return callWithAsyncErrorHandling(\n source,\n instance,\n 3,\n [onCleanup]\n );\n };\n }\n } else {\n getter = NOOP;\n !!(process.env.NODE_ENV !== \"production\") && warnInvalidSource(source);\n }\n if (cb && deep) {\n const baseGetter = getter;\n getter = () => traverse(baseGetter());\n }\n let cleanup;\n let onCleanup = (fn) => {\n cleanup = effect.onStop = () => {\n callWithErrorHandling(fn, instance, 4);\n cleanup = effect.onStop = void 0;\n };\n };\n let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE;\n const job = () => {\n if (!effect.active || !effect.dirty) {\n return;\n }\n if (cb) {\n const newValue = effect.run();\n if (deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => hasChanged(v, oldValue[i])) : hasChanged(newValue, oldValue)) || false) {\n if (cleanup) {\n cleanup();\n }\n callWithAsyncErrorHandling(cb, instance, 3, [\n newValue,\n // pass undefined as the old value when it's changed for the first time\n oldValue === INITIAL_WATCHER_VALUE ? void 0 : isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE ? [] : oldValue,\n onCleanup\n ]);\n oldValue = newValue;\n }\n } else {\n effect.run();\n }\n };\n job.allowRecurse = !!cb;\n let scheduler;\n if (flush === \"sync\") {\n scheduler = job;\n } else if (flush === \"post\") {\n scheduler = () => queuePostRenderEffect$1(job, instance && instance.suspense);\n } else {\n job.pre = true;\n if (instance)\n job.id = instance.uid;\n scheduler = () => queueJob(job);\n }\n const effect = new ReactiveEffect(getter, NOOP, scheduler);\n const scope = getCurrentScope();\n const unwatch = () => {\n effect.stop();\n if (scope) {\n remove(scope.effects, effect);\n }\n };\n if (!!(process.env.NODE_ENV !== \"production\")) {\n effect.onTrack = onTrack;\n effect.onTrigger = onTrigger;\n }\n if (cb) {\n if (immediate) {\n job();\n } else {\n oldValue = effect.run();\n }\n } else if (flush === \"post\") {\n queuePostRenderEffect$1(\n effect.run.bind(effect),\n instance && instance.suspense\n );\n } else {\n effect.run();\n }\n return unwatch;\n}\nfunction instanceWatch(source, value, options) {\n const publicThis = this.proxy;\n const getter = isString(source) ? source.includes(\".\") ? createPathGetter(publicThis, source) : () => publicThis[source] : source.bind(publicThis, publicThis);\n let cb;\n if (isFunction(value)) {\n cb = value;\n } else {\n cb = value.handler;\n options = value;\n }\n const reset = setCurrentInstance(this);\n const res = doWatch(getter, cb.bind(publicThis), options);\n reset();\n return res;\n}\nfunction createPathGetter(ctx, path) {\n const segments = path.split(\".\");\n return () => {\n let cur = ctx;\n for (let i = 0; i < segments.length && cur; i++) {\n cur = cur[segments[i]];\n }\n return cur;\n };\n}\nfunction traverse(value, depth, currentDepth = 0, seen) {\n if (!isObject(value) || value[\"__v_skip\"]) {\n return value;\n }\n if (depth && depth > 0) {\n if (currentDepth >= depth) {\n return value;\n }\n currentDepth++;\n }\n seen = seen || /* @__PURE__ */ new Set();\n if (seen.has(value)) {\n return value;\n }\n seen.add(value);\n if (isRef(value)) {\n traverse(value.value, depth, currentDepth, seen);\n } else if (isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n traverse(value[i], depth, currentDepth, seen);\n }\n } else if (isSet(value) || isMap(value)) {\n value.forEach((v) => {\n traverse(v, depth, currentDepth, seen);\n });\n } else if (isPlainObject(value)) {\n for (const key in value) {\n traverse(value[key], depth, currentDepth, seen);\n }\n }\n return value;\n}\n\nfunction validateDirectiveName(name) {\n if (isBuiltInDirective(name)) {\n warn$1(\"Do not use built-in directive ids as custom directive id: \" + name);\n }\n}\nfunction withDirectives(vnode, directives) {\n if (currentRenderingInstance === null) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`withDirectives can only be used inside render functions.`);\n return vnode;\n }\n const instance = getExposeProxy(currentRenderingInstance) || currentRenderingInstance.proxy;\n const bindings = vnode.dirs || (vnode.dirs = []);\n for (let i = 0; i < directives.length; i++) {\n let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i];\n if (dir) {\n if (isFunction(dir)) {\n dir = {\n mounted: dir,\n updated: dir\n };\n }\n if (dir.deep) {\n traverse(value);\n }\n bindings.push({\n dir,\n instance,\n value,\n oldValue: void 0,\n arg,\n modifiers\n });\n }\n }\n return vnode;\n}\n\nfunction createAppContext() {\n return {\n app: null,\n config: {\n isNativeTag: NO,\n performance: false,\n globalProperties: {},\n optionMergeStrategies: {},\n errorHandler: void 0,\n warnHandler: void 0,\n compilerOptions: {}\n },\n mixins: [],\n components: {},\n directives: {},\n provides: /* @__PURE__ */ Object.create(null),\n optionsCache: /* @__PURE__ */ new WeakMap(),\n propsCache: /* @__PURE__ */ new WeakMap(),\n emitsCache: /* @__PURE__ */ new WeakMap()\n };\n}\nlet uid$1 = 0;\nfunction createAppAPI(render, hydrate) {\n return function createApp(rootComponent, rootProps = null) {\n if (!isFunction(rootComponent)) {\n rootComponent = extend({}, rootComponent);\n }\n if (rootProps != null && !isObject(rootProps)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`root props passed to app.mount() must be an object.`);\n rootProps = null;\n }\n const context = createAppContext();\n const installedPlugins = /* @__PURE__ */ new WeakSet();\n const app = context.app = {\n _uid: uid$1++,\n _component: rootComponent,\n _props: rootProps,\n _container: null,\n _context: context,\n _instance: null,\n version,\n get config() {\n return context.config;\n },\n set config(v) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `app.config cannot be replaced. Modify individual options instead.`\n );\n }\n },\n use(plugin, ...options) {\n if (installedPlugins.has(plugin)) {\n !!(process.env.NODE_ENV !== \"production\") && warn$1(`Plugin has already been applied to target app.`);\n } else if (plugin && isFunction(plugin.install)) {\n installedPlugins.add(plugin);\n plugin.install(app, ...options);\n } else if (isFunction(plugin)) {\n installedPlugins.add(plugin);\n plugin(app, ...options);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n `A plugin must either be a function or an object with an \"install\" function.`\n );\n }\n return app;\n },\n mixin(mixin) {\n if (__VUE_OPTIONS_API__) {\n if (!context.mixins.includes(mixin)) {\n context.mixins.push(mixin);\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\n \"Mixin has already been applied to target app\" + (mixin.name ? `: ${mixin.name}` : \"\")\n );\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(\"Mixins are only available in builds supporting Options API\");\n }\n return app;\n },\n component(name, component) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateComponentName(name, context.config);\n }\n if (!component) {\n return context.components[name];\n }\n if (!!(process.env.NODE_ENV !== \"production\") && context.components[name]) {\n warn$1(`Component \"${name}\" has already been registered in target app.`);\n }\n context.components[name] = component;\n return app;\n },\n directive(name, directive) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n validateDirectiveName(name);\n }\n if (!directive) {\n return context.directives[name];\n }\n if (!!(process.env.NODE_ENV !== \"production\") && context.directives[name]) {\n warn$1(`Directive \"${name}\" has already been registered in target app.`);\n }\n context.directives[name] = directive;\n return app;\n },\n // fixed by xxxxxx\n mount() {\n },\n // fixed by xxxxxx\n unmount() {\n },\n provide(key, value) {\n if (!!(process.env.NODE_ENV !== \"production\") && key in context.provides) {\n warn$1(\n `App already provides property with key \"${String(key)}\". It will be overwritten with the new value.`\n );\n }\n context.provides[key] = value;\n return app;\n },\n runWithContext(fn) {\n const lastApp = currentApp;\n currentApp = app;\n try {\n return fn();\n } finally {\n currentApp = lastApp;\n }\n }\n };\n return app;\n };\n}\nlet currentApp = null;\n\nfunction provide(key, value) {\n if (!currentInstance) {\n if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`provide() can only be used inside setup().`);\n }\n } else {\n let provides = currentInstance.provides;\n const parentProvides = currentInstance.parent && currentInstance.parent.provides;\n if (parentProvides === provides) {\n provides = currentInstance.provides = Object.create(parentProvides);\n }\n provides[key] = value;\n if (currentInstance.type.mpType === \"app\") {\n currentInstance.appContext.app.provide(key, value);\n }\n }\n}\nfunction inject(key, defaultValue, treatDefaultAsFactory = false) {\n const instance = currentInstance || currentRenderingInstance;\n if (instance || currentApp) {\n const provides = instance ? instance.parent == null ? instance.vnode.appContext && instance.vnode.appContext.provides : instance.parent.provides : currentApp._context.provides;\n if (provides && key in provides) {\n return provides[key];\n } else if (arguments.length > 1) {\n return treatDefaultAsFactory && isFunction(defaultValue) ? defaultValue.call(instance && instance.proxy) : defaultValue;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`injection \"${String(key)}\" not found.`);\n }\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n warn$1(`inject() can only be used inside setup() or functional components.`);\n }\n}\nfunction hasInjectionContext() {\n return !!(currentInstance || currentRenderingInstance || currentApp);\n}\n\n/*! #__NO_SIDE_EFFECTS__ */\n// @__NO_SIDE_EFFECTS__\nfunction defineComponent(options, extraOptions) {\n return isFunction(options) ? (\n // #8326: extend call and options.name access are considered side-effects\n // by Rollup, so we have to wrap it in a pure-annotated IIFE.\n /* @__PURE__ */ (() => extend({ name: options.name }, extraOptions, { setup: options }))()\n ) : options;\n}\n\nconst isKeepAlive = (vnode) => vnode.type.__isKeepAlive;\nfunction onActivated(hook, target) {\n registerKeepAliveHook(hook, \"a\", target);\n}\nfunction onDeactivated(hook, target) {\n registerKeepAliveHook(hook, \"da\", target);\n}\nfunction registerKeepAliveHook(hook, type, target = currentInstance) {\n const wrappedHook = hook.__wdc || (hook.__wdc = () => {\n let current = target;\n while (current) {\n if (current.isDeactivated) {\n return;\n }\n current = current.parent;\n }\n return hook();\n });\n injectHook(type, wrappedHook, target);\n if (target) {\n let current = target.parent;\n while (current && current.parent) {\n if (isKeepAlive(current.parent.vnode)) {\n injectToKeepAliveRoot(wrappedHook, type, target, current);\n }\n current = current.parent;\n }\n }\n}\nfunction injectToKeepAliveRoot(hook, type, target, keepAliveRoot) {\n const injected = injectHook(\n type,\n hook,\n keepAliveRoot,\n true\n /* prepend */\n );\n onUnmounted(() => {\n remove(keepAliveRoot[type], injected);\n }, target);\n}\n\nfunction injectHook(type, hook, target = currentInstance, prepend = false) {\n if (target) {\n if (isRootHook(type)) {\n target = target.root;\n }\n const hooks = target[type] || (target[type] = []);\n const wrappedHook = hook.__weh || (hook.__weh = (...args) => {\n if (target.isUnmounted) {\n return;\n }\n pauseTracking();\n const reset = setCurrentInstance(target);\n const res = callWithAsyncErrorHandling(hook, target, type, args);\n reset();\n resetTracking();\n return res;\n });\n if (prepend) {\n hooks.unshift(wrappedHook);\n } else {\n hooks.push(wrappedHook);\n }\n return wrappedHook;\n } else if (!!(process.env.NODE_ENV !== \"production\")) {\n const apiName = toHandlerKey(\n (ErrorTypeStrings[type] || type.replace(/^on/, \"\")).replace(/ hook$/, \"\")\n );\n warn$1(\n `${apiName} is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().` + (``)\n );\n }\n}\nconst createHook = (lifecycle) => (hook, target = currentInstance) => (\n // post-create lifecycle registrations are noops during SSR (except for serverPrefetch)\n (!isInSSRComponentSetup || lifecycle === \"sp\") && injectHook(lifecycle, (...args) => hook(...args), target)\n);\nconst onBeforeMount = createHook(\"bm\");\nconst onMounted = createHook(\"m\");\nconst onBeforeUpdate = createHook(\"bu\");\nconst onUpdated = createHook(\"u\");\nconst onBeforeUnmount = createHook(\"bum\");\nconst onUnmounted = createHook(\"um\");\nconst onServerPrefetch = createHook(\"sp\");\nconst onRenderTriggered = createHook(\n \"rtg\"\n);\nconst onRenderTracked = createHook(\n \"rtc\"\n);\nfunction onErrorCaptured(hook, target = currentInstance) {\n injectHook(\"ec\", hook, target);\n}\n\nfunction toHandlers(obj, preserveCaseIfNecessary) {\n const ret = {};\n if (!!(process.env.NODE_ENV !== \"production\") && !isObject(obj)) {\n warn$1(`v-on with no argument expects an object value.`);\n return ret;\n }\n for (const key in obj) {\n ret[preserveCaseIfNecessary && /[A-Z]/.test(key) ? `on:${key}` : toHandlerKey(key)] = obj[key];\n }\n return ret;\n}\n\nconst getPublicInstance = (i) => {\n if (!i)\n return null;\n if (isStatefulComponent(i))\n return getExposeProxy(i) || i.proxy;\n return getPublicInstance(i.parent);\n};\nfunction getComponentInternalInstance(i) {\n return i;\n}\nconst publicPropertiesMap = (\n // Move PURE marker to new line to workaround compiler discarding it\n // due to type annotation\n /* @__PURE__ */ extend(/* @__PURE__ */ Object.create(null), {\n // fixed by xxxxxx\n $: getComponentInternalInstance,\n // fixed by xxxxxx vue-i18n 在 dev 模式,访问了 $el,故模拟一个假的\n // $el: i => i.vnode.el,\n $el: (i) => i.__$el || (i.__$el = {}),\n $data: (i) => i.data,\n $props: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.props) : i.props,\n $attrs: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.attrs) : i.attrs,\n $slots: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.slots) : i.slots,\n $refs: (i) => !!(process.env.NODE_ENV !== \"production\") ? shallowReadonly(i.refs) : i.refs,\n $parent: (i) => getPublicInstance(i.parent),\n $root: (i) => getPublicInstance(i.root),\n $emit: (i) => i.emit,\n $options: (i) => __VUE_OPTIONS_API__ ? resolveMergedOptions(i) : i.type,\n $forceUpdate: (i) => i.f || (i.f = () => {\n i.effect.dirty = true;\n queueJob(i.update);\n }),\n // $nextTick: i => i.n || (i.n = nextTick.bind(i.proxy!)),// fixed by xxxxxx\n $watch: (i) => __VUE_OPTIONS_API__ ? instanceWatch.bind(i) : NOOP\n })\n);\nconst isReservedPrefix = (key) => key === \"_\" || key === \"$\";\nconst hasSetupBinding = (state, key) => state !== EMPTY_OBJ && !state.__isScriptSetup && hasOwn(state, key);\nconst PublicInstanceProxyHandlers = {\n get({ _: instance }, key) {\n const { ctx, setupState, data, props, accessCache, type, appContext } = instance;\n if (!!(process.env.NODE_ENV !== \"production\") && key === \"__isVue\") {\n return true;\n }\n let normalizedProps;\n if (key[0] !== \"$\") {\n const n = accessCache[key];\n if (n !== void 0) {\n switch (n) {\n case 1 /* SETUP */:\n return setupState[key];\n case 2 /* DATA */:\n return data[key];\n case 4 /* CONTEXT */:\n return ctx[key];\n case 3 /* PROPS */:\n return props[key];\n }\n } else if (hasSetupBinding(setupState, key)) {\n accessCache[key] = 1 /* SETUP */;\n return setupState[key];\n } else if (data !== EMPTY_OBJ && hasOwn(data, key)) {\n accessCache[key] = 2 /* DATA */;\n return data[key];\n } else if (\n // only cache other properties when instance has declared (thus stable)\n // props\n (normalizedProps = instance.propsOptions[0]) && hasOwn(normalizedProps, key)\n ) {\n accessCache[key] = 3 /* PROPS */;\n return props[key];\n } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {\n accessCache[key] = 4 /* CONTEXT */;\n return ctx[key];\n } else if (!__VUE_OPTIONS_API__ || shouldCacheAccess) {\n accessCache[key] = 0 /* OTHER */;\n }\n }\n const publicGetter = publicPropertiesMap[key];\n let cssModule, globalProperties;\n if (publicGetter) {\n if (key === \"$attrs\") {\n track(instance, \"get\", key);\n !!(process.env.NODE_ENV !== \"production\") && markAttrsAccessed();\n } else if (!!(process.env.NODE_ENV !== \"production\") && key === \"$slots\") {\n track(instance, \"get\", key);\n }\n return publicGetter(instance);\n } else if (\n // css module (injected by vue-loader)\n (cssModule = type.__cssModules) && (cssModule = cssModule[key])\n ) {\n return cssModule;\n } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) {\n accessCache[key] = 4 /* CONTEXT */;\n return ctx[key];\n } else if (\n // global properties\n globalProperties = appContext.config.globalProperties, hasOwn(globalProperties, key)\n ) {\n {\n return globalProperties[key];\n }\n } else if (!!(process.env.NODE_ENV !== \"production\") && currentRenderingInstance && (!isString(key) || // #1091 avoid internal isRef/isVNode checks on component instance leading\n // to infinite warning loop\n key.indexOf(\"__v\") !== 0)) {\n if (data !== EMPTY_OBJ && isReservedPrefix(key[0]) && hasOwn(data, key)) {\n warn$1(\n `Property ${JSON.stringify(\n key\n )} must be accessed via $data because it starts with a reserved character (\"$\" or \"_\") and is not proxied on the render context.`\n );\n } else if (instance === currentRenderingInstance) {\n warn$1(\n `Property ${JSON.stringify(key)} was accessed during render but is not defined on instance.`\n );\n }\n }\n },\n set({ _: instance }, key, value) {\n const { data, setupState, ctx } = instance;\n if (hasSetupBinding(setupState, key)) {\n setupState[key] = value;\n return true;\n } else if (!!(process.env.NODE_ENV !== \"production\") && setupState.__isScriptSetup && hasOwn(setupState, key)) {\n warn$1(`Cannot mutate \r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/account/form.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni","put","post"],"mappings":";;;AA0BA,MAAK,YAAU;AAAA,EACd,OAAM;AACL,WAAO;AAAA,MACN,IAAI;AAAA,MACJ,MAAM,EAAE,MAAM,IAAI,MAAM,QAAQ,UAAU,IAAI,aAAa,IAAI,gBAAgB,GAAI;AAAA,MACnF,UAAU;AAAA,MACV,OAAO;AAAA,QACN,EAAE,KAAK,QAAQ,MAAM,KAAM;AAAA,QAC3B,EAAE,KAAK,QAAQ,MAAM,OAAQ;AAAA,QAC7B,EAAE,KAAK,UAAU,MAAM,KAAM;AAAA,QAC7B,EAAE,KAAK,UAAU,MAAM,MAAO;AAAA,QAC9B,EAAE,KAAK,SAAS,MAAM,KAAK;AAAA,MAC5B;AAAA,IACD;AAAA,EACA;AAAA,EACD,OAAO,GAAE;AAAE,SAAK,KAAK,KAAK,EAAE,KAAK,OAAO,EAAE,EAAE,IAAI;AAAM,QAAI,KAAK;AAAI,WAAK,KAAI;AAAA,EAAK;AAAA,EACjF,SAAS;AAAA,IACR,UAAU,GAAE;AAAE,YAAM,IAAI,EAAC,MAAK,MAAM,MAAK,QAAQ,QAAO,MAAM,QAAO,OAAO,OAAM,KAAI;AAAG,aAAO,EAAE,CAAC,KAAG;AAAA,IAAG;AAAA,IACzG,MAAM,OAAM;AAAE,UAAI;AAAE,cAAM,OAAO,MAAMA,YAAAA,IAAI,eAAe;AAAG,cAAM,KAAK,MAAM,QAAQ,IAAI,IAAE,QAAM,6BAAM,SAAM,CAAE,GAAG,KAAK,OAAG,EAAE,MAAI,KAAK,EAAE;AAAG,YAAI,GAAG;AAAE,eAAK,OAAK,EAAE,MAAK,EAAE,MAAM,MAAK,EAAE,MAAM,UAAS,EAAE,aAAW,EAAE,YAAU,IAAI,aAAY,EAAE,gBAAc,EAAE,eAAa,IAAI,gBAAe,GAAG;AAAA,QAAI;AAAA,MAAA,SAAQ,GAAE;AAAA,MAAA;AAAA,IAAI;AAAA,IACnT,MAAM,OAAM;AACX,UAAI,CAAC,KAAK,KAAK,MAAM;AAAEC,sBAAG,MAAC,UAAU,EAAE,OAAO,SAAS,MAAM,OAAO,CAAC;AAAG;AAAA,MAAO;AAC/E,UAAI;AACH,cAAM,OAAO,EAAE,GAAG,KAAK,MAAM,gBAAgB,OAAO,KAAK,KAAK,kBAAgB,CAAC,EAAE;AACjF,YAAI,KAAK;AAAI,gBAAMC,gBAAI,iBAAiB,KAAK,EAAE,IAAI,IAAI;AAAA;AAClD,gBAAMC,YAAAA,KAAK,iBAAiB,EAAE,GAAG,MAAM,QAAQ,GAAG;AACvDF,sBAAG,MAAC,UAAU,EAAE,OAAO,OAAO,MAAM,WAAW;AAC/C,mBAAW,MAAIA,cAAAA,MAAI,aAAY,GAAI,GAAG;AAAA,eAC/B,GAAG;AAAEA,sBAAAA,MAAI,UAAU,EAAE,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,MAAE;AAAA,IAC7D;AAAA,EACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvDA,GAAG,WAAW,eAAe;"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/account/ledger.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/account/ledger.js.map new file mode 100644 index 0000000..2dd2843 --- /dev/null +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/account/ledger.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ledger.js","sources":["pages/account/ledger.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvYWNjb3VudC9sZWRnZXIudnVl"],"sourcesContent":["\r\n\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/account/ledger.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni"],"mappings":";;;AA8BA,MAAK,YAAU;AAAA,EACd,OAAO;AACN,WAAO,EAAE,WAAW,MAAM,WAAW,IAAI,SAAS,IAAI,MAAM,CAAE,GAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,EAAE;AAAA,EAC7G;AAAA,EACD,OAAO,OAAO;AACb,SAAK,YAAY,OAAO,SAAS,MAAM,EAAE;AACzC,SAAK,UAAU;AACf,SAAK,KAAK;AAAA,EACV;AAAA,EACD,SAAS;AAAA,IACR,YAAY;AAEX,YAAM,MAAM,oBAAI,KAAK;AACrB,YAAM,IAAI,IAAI,YAAW,GAAI,IAAI,IAAI,SAAQ,IAAG;AAChD,WAAK,YAAY,GAAG,CAAC,IAAI,OAAO,CAAC,EAAE,SAAS,GAAE,GAAG,CAAC;AAClD,YAAM,UAAU,IAAI,KAAK,GAAG,GAAG,CAAC,EAAE,QAAQ;AAC1C,WAAK,UAAU,GAAG,CAAC,IAAI,OAAO,CAAC,EAAE,SAAS,GAAE,GAAG,CAAC,IAAI,OAAO,OAAO,EAAE,SAAS,GAAE,GAAG,CAAC;AAAA,IACnF;AAAA,IACD,MAAM,KAAK,OAAK,GAAG,OAAK,IAAI;AAC3B,UAAI;AACH,cAAM,MAAM,MAAMA,gBAAI,iBAAiB,KAAK,SAAS,WAAW,EAAE,WAAW,KAAK,WAAW,SAAS,KAAK,SAAS,MAAM,MAAM;AAChI,aAAK,OAAQ,OAAO,IAAI,QAAS,CAAC;AAClC,aAAK,UAAU,OAAO,OAAO,IAAI,WAAW,CAAC;AAC7C,aAAK,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC;AAC3C,aAAK,UAAU,OAAO,OAAO,IAAI,WAAW,CAAC;AAC7C,aAAK,SAAS,OAAO,OAAO,IAAI,UAAU,CAAC;AAAA,MAC5C,SAAS,GAAG;AACXC,sBAAG,MAAC,UAAU,EAAE,OAAO,QAAQ,MAAM,QAAQ;AAAA,MAC9C;AAAA,IACA;AAAA,IACD,IAAI,GAAG;AAAE,cAAQ,OAAO,MAAM,WAAW,IAAI,OAAO,KAAG,CAAC,GAAG,QAAQ,CAAC;AAAA,IAAG;AAAA,IACvE,WAAW,GAAG;AAAE,UAAI,CAAC;AAAG,eAAO;AAAK,UAAI;AAAE,cAAM,IAAE,IAAI,KAAK,CAAC;AAAG,cAAM,MAAI,OAAG,OAAO,CAAC,EAAE,SAAS,GAAE,GAAG;AAAG,eAAO,GAAG,EAAE,YAAa,CAAA,IAAI,IAAI,EAAE,SAAU,IAAC,CAAC,CAAC,IAAI,IAAI,EAAE,QAAO,CAAE,CAAC,IAAI,IAAI,EAAE,SAAQ,CAAE,CAAC,IAAI,IAAI,EAAE,WAAU,CAAE,CAAC;AAAA,MAAG,SAAQ,GAAE;AAAE,eAAO;AAAA,MAAA;AAAA,IAAI;AAAA,EAClP;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9DA,GAAG,WAAW,eAAe;"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/account/select.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/account/select.js.map index 4e7e406..6b95ced 100644 --- a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/account/select.js.map +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/account/select.js.map @@ -1 +1 @@ -{"version":3,"file":"select.js","sources":["pages/account/select.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvYWNjb3VudC9zZWxlY3QudnVl"],"sourcesContent":["\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/account/select.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni"],"mappings":";;;AAaC,MAAM,WAAW,EAAE,MAAM,MAAM,MAAM,MAAM,QAAQ,OAAO,QAAQ,MAAM,OAAO,KAAK;AACpF,MAAK,YAAU;AAAA,EACd,OAAO;AAAE,WAAO,EAAE,UAAU,CAAG,EAAA;AAAA,EAAG;AAAA,EAClC,MAAM,SAAS;AACd,QAAI;AACH,YAAM,MAAM,MAAMA,YAAG,IAAC,eAAe;AACrC,WAAK,WAAW,MAAM,QAAQ,GAAG,IAAI,OAAO,2BAAK,SAAQ;aAClD,GAAG;AAAEC,oBAAAA,MAAI,UAAU,EAAE,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,IAAE;AAAA,EAC5D;AAAA,EACD,SAAS;AAAA,IACR,OAAO,GAAG;AACT,YAAM,SAAS,gBAAiB,EAAC,gBAAe,EAAG,SAAO,CAAC;AAC3D,UAAI,UAAU,OAAO,KAAK;AACzB,eAAO,IAAI,oBAAoB,EAAE;AACjC,eAAO,IAAI,sBAAsB,EAAE;AAAA,MACpC;AACAA,oBAAAA,MAAI,aAAa;AAAA,IACjB;AAAA,IACD,UAAU,GAAG;AAAE,aAAO,SAAS,CAAC,KAAK;AAAA,IAAE;AAAA,EACxC;AACD;;;;;;;;;;;;;;;;AChCD,GAAG,WAAW,eAAe;"} \ No newline at end of file +{"version":3,"file":"select.js","sources":["pages/account/select.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvYWNjb3VudC9zZWxlY3QudnVl"],"sourcesContent":["\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/account/select.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni"],"mappings":";;;AAcC,MAAM,WAAW,EAAE,MAAM,MAAM,MAAM,MAAM,QAAQ,OAAO,QAAQ,MAAM,OAAO,KAAK;AACpF,MAAK,YAAU;AAAA,EACd,OAAO;AAAE,WAAO,EAAE,UAAU,CAAA,GAAI,MAAM;EAAU;AAAA,EAChD,MAAM,OAAO,GAAG;AACf,SAAK,OAAQ,KAAK,EAAE,QAAS;AAC7B,QAAI;AACH,YAAM,MAAM,MAAMA,YAAG,IAAC,eAAe;AACrC,WAAK,WAAW,MAAM,QAAQ,GAAG,IAAI,OAAO,2BAAK,SAAQ;aAClD,GAAG;AAAEC,oBAAAA,MAAI,UAAU,EAAE,OAAO,QAAQ,MAAM,OAAO,CAAC;AAAA,IAAE;AAAA,EAC5D;AAAA,EACD,SAAS;AAAA,IACR,OAAO,GAAG;AACT,UAAI,KAAK,SAAS,QAAQ;AACzB,cAAM,SAAS,gBAAiB,EAAC,gBAAe,EAAG,SAAO,CAAC;AAC3D,YAAI,UAAU,OAAO,KAAK;AACzB,iBAAO,IAAI,oBAAoB,EAAE;AACjC,iBAAO,IAAI,sBAAsB,EAAE;AAAA,QACpC;AACAA,sBAAAA,MAAI,aAAa;AAAA,aACX;AACNA,4BAAI,WAAW,EAAE,KAAK,4BAA4B,EAAE,EAAE,IAAI;AAAA,MAC3D;AAAA,IACA;AAAA,IACD,SAAS;AAAEA,oBAAAA,MAAI,WAAW,EAAE,KAAK,sBAAoB,CAAG;AAAA,IAAG;AAAA,IAC3D,UAAU,GAAG;AAAE,aAAO,SAAS,CAAC,KAAK;AAAA,IAAE;AAAA,EACxC;AACD;;;;;;;;;;;;;;;;;ACvCD,GAAG,WAAW,eAAe;"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map index ae31b43..b2b5b13 100644 --- a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/index/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["pages/index/index.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvaW5kZXgvaW5kZXgudnVl"],"sourcesContent":["\n\n\n\n\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/index/index.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["pages/index/index.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvaW5kZXgvaW5kZXgudnVl"],"sourcesContent":["\n\n\n\n\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/index/index.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni"],"mappings":"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"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/my/about.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/my/about.js.map new file mode 100644 index 0000000..c9a09d7 --- /dev/null +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/my/about.js.map @@ -0,0 +1 @@ +{"version":3,"file":"about.js","sources":["pages/my/about.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbXkvYWJvdXQudnVl"],"sourcesContent":["\r\n\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/my/about.vue'\nwx.createPage(MiniProgramPage)"],"names":["uni"],"mappings":";;;AA8BA,MAAK,YAAU;AAAA,EACd,SAAS;AAAA,IACR,aAAa;AACZA,0BAAI,UAAU,EAAE,OAAO,QAAQ,SAAS,cAAc,YAAY,OAAO;AAAA,IACzE;AAAA,IACD,YAAY;AACXA,0BAAI,UAAU,EAAE,OAAO,QAAQ,SAAS,cAAc,YAAY,OAAO;AAAA,IACzE;AAAA,IACD,gBAAgB;AACfA,oBAAG,MAAC,UAAU,EAAE,OAAO,QAAQ,MAAM,QAAQ;AAAA,IAC9C;AAAA,EACD;AACD;;;;;;;;;;ACzCA,GAAG,WAAW,eAAe;"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/my/index.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/my/index.js.map new file mode 100644 index 0000000..6b0dba4 --- /dev/null +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/my/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sources":["pages/my/index.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvbXkvaW5kZXgudnVl"],"sourcesContent":["\r\n\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/my/index.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni"],"mappings":";;;AAyEA,MAAK,YAAU;AAAA,EACd,OAAO;AACN,WAAO;AAAA,MACN,WAAW;AAAA,MACX,UAAU;AAAA,MACV,QAAQ;AAAA,IACT;AAAA,EACA;AAAA,EACD,SAAS;AACR,SAAK,aAAa;AAAA,EAClB;AAAA,EACD,UAAU;AAAA,IACT,gBAAgB;AACf,YAAM,IAAI,OAAO,KAAK,UAAU,EAAE;AAClC,aAAO,EAAE,WAAW,KAAK,EAAE,MAAM,GAAE,CAAC,IAAI,SAAS,EAAE,MAAM,CAAC,IAAK,KAAK;AAAA,IACrE;AAAA,EACA;AAAA,EACD,SAAS;AAAA,IACR,MAAM,eAAe;AAEpB,UAAI;AAAE,cAAMA,YAAAA,IAAI,yBAAyB;AAAA,MAAE,SAAQ,GAAG;AAAA,MAAC;AAEvD,UAAI;AACH,cAAM,YAAYC,cAAG,MAAC,eAAe,WAAW,KAAK;AACrD,cAAM,SAASA,cAAG,MAAC,eAAe,aAAa,KAAK;AACpD,cAAM,QAAQA,cAAG,MAAC,eAAe,aAAa,KAAK;AACnD,YAAI;AAAW,eAAK,WAAW;AAC/B,YAAI;AAAQ,eAAK,YAAY;AAC7B,aAAK,SAAS;AAAA,eACP,GAAG;AAAA,MAAC;AAAA,IACZ;AAAA,IACD,gBAAgB;AACf,WAAK,YAAY;AAAA,IACjB;AAAA,IACD,QAAQ;AAAEA,oBAAG,MAAC,UAAU,EAAE,OAAO,cAAc,MAAM,OAAK,CAAG;AAAA,IAAG;AAAA,IAChE,aAAa;AAAEA,oBAAAA,MAAI,WAAW,EAAE,KAAK,sBAAoB,CAAG;AAAA,IAAG;AAAA,IAC/D,aAAa;AAAEA,oBAAAA,MAAI,WAAW,EAAE,KAAK,yBAAuB,CAAG;AAAA,IAAG;AAAA,IAClE,aAAa;AAAEA,oBAAAA,MAAI,WAAW,EAAE,KAAK,yBAAuB,CAAG;AAAA,IAAG;AAAA,IAClE,kBAAkB;AAAEA,oBAAG,MAAC,UAAU,EAAE,OAAO,aAAa,MAAM,OAAO,CAAC;AAAA,IAAG;AAAA,IACzE,SAAS;AAAEA,oBAAG,MAAC,UAAU,EAAE,OAAO,aAAa,MAAM,OAAK,CAAG;AAAA,IAAG;AAAA,IAChE,cAAc;AAAEA,oBAAG,MAAC,UAAU,EAAE,OAAO,cAAc,MAAM,OAAK,CAAG;AAAA,IAAG;AAAA,IACtE,oBAAoB;AAAEA,oBAAAA,MAAI,WAAW,EAAE,KAAK,0BAA0B,CAAC;AAAA,IAAG;AAAA,IAC1E,iBAAiB;AAAEA,oBAAG,MAAC,UAAU,EAAE,OAAO,aAAa,MAAM,OAAO,CAAC;AAAA,IAAG;AAAA,IACxE,UAAU;AAAEA,oBAAAA,MAAI,WAAW,EAAE,KAAK,kBAAgB,CAAG;AAAA,IAAG;AAAA,IACxD,SAAS;AACR,UAAI;AACHA,sBAAG,MAAC,kBAAkB,OAAO;AAC7BA,sBAAG,MAAC,kBAAkB,aAAa;AACnCA,sBAAG,MAAC,kBAAkB,WAAW;AACjCA,sBAAG,MAAC,kBAAkB,aAAa;AACnCA,sBAAG,MAAC,kBAAkB,WAAW;AACjCA,sBAAG,MAAC,UAAU,EAAE,OAAO,OAAO,MAAM,QAAQ;AAC5C,mBAAW,MAAM;AAAEA,wBAAAA,MAAI,SAAS,EAAE,KAAK,qBAAmB,CAAG;AAAA,QAAG,GAAE,GAAG;AAAA,MACtE,SAAQ,GAAG;AACVA,sBAAAA,MAAI,SAAS,EAAE,KAAK,sBAAsB;AAAA,MAC3C;AAAA,IACD;AAAA,EACD;AACD;;;;;;;;;;;;;;;;;;;;;AClIA,GAAG,WAAW,eAAe;"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/order/create.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/order/create.js.map index 550ce9a..bbf1b19 100644 --- a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/order/create.js.map +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/order/create.js.map @@ -1 +1 @@ -{"version":3,"file":"create.js","sources":["pages/order/create.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvb3JkZXIvY3JlYXRlLnZ1ZQ"],"sourcesContent":["\n\n\n\n\n\n\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/order/create.vue'\nwx.createPage(MiniProgramPage)"],"names":["INCOME_CATEGORIES","EXPENSE_CATEGORIES","get","uni","post"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"create.js","sources":["pages/order/create.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvb3JkZXIvY3JlYXRlLnZ1ZQ"],"sourcesContent":["\n\n\n\n\n\n\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/order/create.vue'\nwx.createPage(MiniProgramPage)"],"names":["INCOME_CATEGORIES","EXPENSE_CATEGORIES","get","uni","post"],"mappings":"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"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/report/entry.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/report/entry.js.map new file mode 100644 index 0000000..ce5c88e --- /dev/null +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/report/entry.js.map @@ -0,0 +1 @@ +{"version":3,"file":"entry.js","sources":["pages/report/entry.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvcmVwb3J0L2VudHJ5LnZ1ZQ"],"sourcesContent":["\r\n\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/report/entry.vue'\nwx.createPage(MiniProgramPage)"],"names":["uni"],"mappings":";;AAwBA,MAAK,YAAU;AAAA,EACd,SAAS;AAAA,IACR,GAAG,MAAM,KAAK;AACb,YAAM,IAAI,QAAQ,mBAAmB,IAAI,CAAC,QAAQ,mBAAmB,OAAK,EAAE,CAAC;AAC7EA,oBAAG,MAAC,WAAW,EAAE,KAAK,uBAAuB,CAAC,IAAI;AAAA,IACnD;AAAA,EACD;AACD;;;;;;;;;;;;;;AC9BA,GAAG,WAAW,eAAe;"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/report/index.js.map b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/report/index.js.map new file mode 100644 index 0000000..2a9d5df --- /dev/null +++ b/frontend/unpackage/dist/dev/.sourcemap/mp-weixin/pages/report/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sources":["pages/report/index.vue","../../../../Downloads/HBuilderX.4.76.2025082103/HBuilderX/plugins/uniapp-cli-vite/uniPage:/cGFnZXMvcmVwb3J0L2luZGV4LnZ1ZQ"],"sourcesContent":["\r\n\r\n\r\n\r\n\r\n\r\n\r\n","import MiniProgramPage from 'C:/Users/21826/Desktop/Wj/PartsInquiry/frontend/pages/report/index.vue'\nwx.createPage(MiniProgramPage)"],"names":["get","uni"],"mappings":"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"} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/app.js b/frontend/unpackage/dist/dev/mp-weixin/app.js index a48928a..ab9bd52 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/app.js +++ b/frontend/unpackage/dist/dev/mp-weixin/app.js @@ -16,7 +16,13 @@ if (!Math) { "./pages/supplier/select.js"; "./pages/supplier/form.js"; "./pages/account/select.js"; + "./pages/account/ledger.js"; + "./pages/account/form.js"; "./pages/detail/index.js"; + "./pages/my/index.js"; + "./pages/my/about.js"; + "./pages/report/index.js"; + "./pages/report/entry.js"; } const _sfc_main = { onLaunch: function() { diff --git a/frontend/unpackage/dist/dev/mp-weixin/app.json b/frontend/unpackage/dist/dev/mp-weixin/app.json index d40b9ad..035070b 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/app.json +++ b/frontend/unpackage/dist/dev/mp-weixin/app.json @@ -14,7 +14,13 @@ "pages/supplier/select", "pages/supplier/form", "pages/account/select", - "pages/detail/index" + "pages/account/ledger", + "pages/account/form", + "pages/detail/index", + "pages/my/index", + "pages/my/about", + "pages/report/index", + "pages/report/entry" ], "window": { "navigationBarTextStyle": "black", diff --git a/frontend/unpackage/dist/dev/mp-weixin/common/vendor.js b/frontend/unpackage/dist/dev/mp-weixin/common/vendor.js index 551d2f9..3ee85b9 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/common/vendor.js +++ b/frontend/unpackage/dist/dev/mp-weixin/common/vendor.js @@ -5219,6 +5219,10 @@ function vFor(source, renderItem) { } return ret; } +function setRef(ref2, id, opts = {}) { + const { $templateRefs } = getCurrentInstance(); + $templateRefs.push({ i: id, r: ref2, k: opts.k, f: opts.f }); +} function withModelModifiers(fn, { number, trim }, isComponent = false) { if (isComponent) { return (...args) => { @@ -5247,6 +5251,7 @@ const e = (target, ...sources) => extend(target, ...sources); const n = (value) => normalizeClass(value); const t = (val) => toDisplayString(val); const p = (props) => renderProps(props); +const sr = (ref2, id, opts) => setRef(ref2, id, opts); const m = (fn, modifiers, isComponent = false) => withModelModifiers(fn, modifiers, isComponent); function createApp$1(rootComponent, rootProps = null) { rootComponent && (rootComponent.mpType = "app"); @@ -7069,7 +7074,7 @@ function isConsoleWritable() { function initRuntimeSocketService() { const hosts = "198.18.0.1,192.168.31.192,127.0.0.1"; const port = "8090"; - const id = "mp-weixin_eSBEHk"; + const id = "mp-weixin_HpGDB1"; const lazy = typeof swan !== "undefined"; let restoreError = lazy ? () => { } : initOnError(); @@ -8026,5 +8031,6 @@ exports.o = o; exports.p = p; exports.resolveComponent = resolveComponent; exports.s = s; +exports.sr = sr; exports.t = t; //# sourceMappingURL=../../.sourcemap/mp-weixin/common/vendor.js.map diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.js b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.js new file mode 100644 index 0000000..895a294 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.js @@ -0,0 +1,102 @@ +"use strict"; +const common_vendor = require("../../common/vendor.js"); +const common_http = require("../../common/http.js"); +const _sfc_main = { + data() { + return { + id: null, + form: { name: "", type: "cash", bankName: "", bankAccount: "", openingBalance: "" }, + showType: false, + types: [ + { key: "cash", name: "现金" }, + { key: "bank", name: "银行存款" }, + { key: "wechat", name: "微信" }, + { key: "alipay", name: "支付宝" }, + { key: "other", name: "其他" } + ] + }; + }, + onLoad(q) { + this.id = q && q.id ? Number(q.id) : null; + if (this.id) + this.load(); + }, + methods: { + typeLabel(t) { + const m = { cash: "现金", bank: "银行存款", wechat: "微信", alipay: "支付宝", other: "其他" }; + return m[t] || t; + }, + async load() { + try { + const list = await common_http.get("/api/accounts"); + const a = (Array.isArray(list) ? list : (list == null ? void 0 : list.list) || []).find((x) => x.id == this.id); + if (a) { + this.form = { name: a.name, type: a.type, bankName: a.bank_name || a.bankName || "", bankAccount: a.bank_account || a.bankAccount || "", openingBalance: "" }; + } + } catch (e) { + } + }, + async save() { + if (!this.form.name) { + common_vendor.index.showToast({ title: "请输入名称", icon: "none" }); + return; + } + try { + const body = { ...this.form, openingBalance: Number(this.form.openingBalance || 0) }; + if (this.id) + await common_http.put(`/api/accounts/${this.id}`, body); + else + await common_http.post("/api/accounts", { ...body, status: 1 }); + common_vendor.index.showToast({ title: "已保存", icon: "success" }); + setTimeout(() => common_vendor.index.navigateBack(), 300); + } catch (e) { + common_vendor.index.showToast({ title: "保存失败", icon: "none" }); + } + } + } +}; +if (!Array) { + const _component_uni_popup = common_vendor.resolveComponent("uni-popup"); + _component_uni_popup(); +} +function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return common_vendor.e({ + a: $data.form.name, + b: common_vendor.o(($event) => $data.form.name = $event.detail.value), + c: common_vendor.t($options.typeLabel($data.form.type)), + d: common_vendor.o(($event) => $data.showType = true), + e: $data.form.type === "bank" + }, $data.form.type === "bank" ? { + f: $data.form.bankName, + g: common_vendor.o(($event) => $data.form.bankName = $event.detail.value) + } : {}, { + h: $data.form.type === "bank" + }, $data.form.type === "bank" ? { + i: $data.form.bankAccount, + j: common_vendor.o(($event) => $data.form.bankAccount = $event.detail.value) + } : {}, { + k: $data.form.openingBalance, + l: common_vendor.o(($event) => $data.form.openingBalance = $event.detail.value), + m: common_vendor.o((...args) => $options.save && $options.save(...args)), + n: common_vendor.f($data.types, (t, k0, i0) => { + return { + a: common_vendor.t(t.name), + b: t.key, + c: common_vendor.o(($event) => { + $data.form.type = t.key; + $data.showType = false; + }, t.key) + }; + }), + o: common_vendor.o(($event) => $data.showType = false), + p: common_vendor.sr("popup", "4430e2e8-0"), + q: common_vendor.o(($event) => $data.showType = $event), + r: common_vendor.p({ + type: "bottom", + modelValue: $data.showType + }) + }); +} +const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); +wx.createPage(MiniProgramPage); +//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/account/form.js.map diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.json b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.json new file mode 100644 index 0000000..be75ea8 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "新增/编辑账户", + "usingComponents": {} +} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.wxml new file mode 100644 index 0000000..fb8fcdc --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.wxml @@ -0,0 +1 @@ +账户名称账户类型{{c}}银行名称银行账号当前余额{{t.a}}取消 \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.wxss new file mode 100644 index 0000000..df94315 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/form.wxss @@ -0,0 +1,23 @@ + +.page { display:flex; flex-direction: column; height: 100vh; +} +.form { background:#fff; +} +.field { display:flex; align-items:center; justify-content: space-between; padding: 18rpx 20rpx; border-bottom:1rpx solid #f3f3f3; +} +.label { color:#666; +} +.input { flex:1; text-align: right; color:#333; +} +.value { color:#333; +} +.actions { margin-top: 20rpx; padding: 0 20rpx; +} +.primary { width: 100%; background: #3c9cff; color:#fff; border-radius: 8rpx; padding: 22rpx 0; +} +.sheet { background:#fff; +} +.sheet-item { padding: 26rpx; text-align:center; border-bottom:1rpx solid #f2f2f2; +} +.sheet-cancel { padding: 26rpx; text-align:center; color:#666; +} diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.js b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.js new file mode 100644 index 0000000..9135a7a --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.js @@ -0,0 +1,83 @@ +"use strict"; +const common_vendor = require("../../common/vendor.js"); +const common_http = require("../../common/http.js"); +const _sfc_main = { + data() { + return { accountId: null, startDate: "", endDate: "", list: [], opening: 0, income: 0, expense: 0, ending: 0 }; + }, + onLoad(query) { + this.accountId = Number(query && query.id); + this.quickInit(); + this.load(); + }, + methods: { + quickInit() { + const now = /* @__PURE__ */ new Date(); + const y = now.getFullYear(), m = now.getMonth() + 1; + this.startDate = `${y}-${String(m).padStart(2, "0")}-01`; + const lastDay = new Date(y, m, 0).getDate(); + this.endDate = `${y}-${String(m).padStart(2, "0")}-${String(lastDay).padStart(2, "0")}`; + }, + async load(page = 1, size = 50) { + try { + const res = await common_http.get(`/api/accounts/${this.accountId}/ledger`, { startDate: this.startDate, endDate: this.endDate, page, size }); + this.list = res && res.list || []; + this.opening = Number(res && res.opening || 0); + this.income = Number(res && res.income || 0); + this.expense = Number(res && res.expense || 0); + this.ending = Number(res && res.ending || 0); + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + fmt(v) { + return (typeof v === "number" ? v : Number(v || 0)).toFixed(2); + }, + formatDate(s) { + if (!s) + return "-"; + try { + const d = new Date(s); + const pad = (n) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`; + } catch (e) { + return s; + } + } + } +}; +function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return { + a: common_vendor.t($data.startDate || "—"), + b: $data.startDate, + c: common_vendor.o((e) => { + $data.startDate = e.detail.value; + $options.load(); + }), + d: common_vendor.t($data.endDate || "—"), + e: $data.endDate, + f: common_vendor.o((e) => { + $data.endDate = e.detail.value; + $options.load(); + }), + g: common_vendor.t($options.fmt($data.income)), + h: common_vendor.t($options.fmt($data.expense)), + i: common_vendor.t($options.fmt($data.opening)), + j: common_vendor.t($options.fmt($data.ending)), + k: common_vendor.f($data.list, (it, k0, i0) => { + return { + a: common_vendor.t(it.src === "other" ? it.category || "其他" : it.remark || "收付款"), + b: common_vendor.t(it.direction === "in" ? "+" : "-"), + c: common_vendor.t($options.fmt(it.amount)), + d: it.direction === "in" ? 1 : "", + e: it.direction === "out" ? 1 : "", + f: common_vendor.t($options.formatDate(it.tx_time || it.txTime)), + g: common_vendor.t(it.remark || "-"), + h: it.id + }; + }) + }; +} +const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); +wx.createPage(MiniProgramPage); +//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/account/ledger.js.map diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.json b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.json new file mode 100644 index 0000000..77c0730 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "账户流水", + "usingComponents": {} +} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.wxml new file mode 100644 index 0000000..711c3ad --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.wxml @@ -0,0 +1 @@ +开始{{a}}结束{{d}}收入{{g}}支出{{h}}期初{{i}}期末{{j}}{{it.a}}{{it.b}}{{it.c}}{{it.f}} · {{it.g}} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.wxss new file mode 100644 index 0000000..4db1690 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/ledger.wxss @@ -0,0 +1,35 @@ + +.page { display:flex; flex-direction: column; height: 100vh; +} +.filters { display:flex; gap: 16rpx; padding: 16rpx; background:#fff; +} +.field { display:flex; justify-content: space-between; align-items:center; padding: 16rpx; border:1rpx solid #eee; border-radius: 12rpx; min-width: 300rpx; +} +.label { color:#666; +} +.value { color:#333; +} +.summary { display:grid; grid-template-columns: repeat(4,1fr); gap: 12rpx; padding: 12rpx 16rpx; background:#fff; border-top:1rpx solid #f1f1f1; border-bottom:1rpx solid #f1f1f1; +} +.sum-item { padding: 12rpx; text-align:center; +} +.k { display:block; color:#888; font-size: 24rpx; +} +.v { display:block; margin-top:6rpx; font-weight:700; color:#333; +} +.list { flex:1; +} +.item { padding: 18rpx 16rpx; border-bottom:1rpx solid #f4f4f4; background:#fff; +} +.row { display:flex; align-items:center; justify-content: space-between; margin-bottom: 6rpx; +} +.title { color:#333; +} +.amount { font-weight:700; +} +.amount.in { color:#2a9d8f; +} +.amount.out { color:#d35b5b; +} +.meta { color:#999; font-size: 24rpx; +} diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.js b/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.js index bea0004..b087fcd 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.js +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.js @@ -4,9 +4,10 @@ const common_http = require("../../common/http.js"); const TYPE_MAP = { cash: "现金", bank: "银行", alipay: "支付宝", wechat: "微信", other: "其他" }; const _sfc_main = { data() { - return { accounts: [] }; + return { accounts: [], mode: "view" }; }, - async onLoad() { + async onLoad(q) { + this.mode = q && q.mode || "view"; try { const res = await common_http.get("/api/accounts"); this.accounts = Array.isArray(res) ? res : (res == null ? void 0 : res.list) || []; @@ -16,12 +17,19 @@ const _sfc_main = { }, methods: { select(a) { - const opener = getCurrentPages()[getCurrentPages().length - 2]; - if (opener && opener.$vm) { - opener.$vm.selectedAccountId = a.id; - opener.$vm.selectedAccountName = a.name; + if (this.mode === "pick") { + const opener = getCurrentPages()[getCurrentPages().length - 2]; + if (opener && opener.$vm) { + opener.$vm.selectedAccountId = a.id; + opener.$vm.selectedAccountName = a.name; + } + common_vendor.index.navigateBack(); + } else { + common_vendor.index.navigateTo({ url: `/pages/account/ledger?id=${a.id}` }); } - common_vendor.index.navigateBack(); + }, + create() { + common_vendor.index.navigateTo({ url: "/pages/account/form" }); }, typeLabel(t) { return TYPE_MAP[t] || t; @@ -39,7 +47,8 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { d: a.id, e: common_vendor.o(($event) => $options.select(a), a.id) }; - }) + }), + b: common_vendor.o((...args) => $options.create && $options.create(...args)) }; } const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxml index 1579e2a..7bf3d7e 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxml +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxml @@ -1 +1 @@ -{{a.a}}{{a.b}} · 余额:{{a.c}} \ No newline at end of file +{{a.a}}{{a.b}} · 余额:{{a.c}} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxss index e15566f..9f5ed72 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxss +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/account/select.wxss @@ -9,3 +9,5 @@ } .meta { color:#888; font-size: 24rpx; } +.fab { position: fixed; right: 32rpx; bottom: 120rpx; width: 100rpx; height: 100rpx; border-radius: 50%; background:#3c9cff; color:#fff; display:flex; align-items:center; justify-content:center; font-size: 52rpx; box-shadow: 0 10rpx 20rpx rgba(0,0,0,0.18); +} diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/index/index.js b/frontend/unpackage/dist/dev/mp-weixin/pages/index/index.js index e848385..241350a 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/pages/index/index.js +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/index/index.js @@ -67,6 +67,10 @@ const _sfc_main = { common_vendor.index.navigateTo({ url: "/pages/customer/select" }); return; } + if (item.key === "account") { + common_vendor.index.navigateTo({ url: "/pages/account/select" }); + return; + } if (item.key === "supplier") { common_vendor.index.navigateTo({ url: "/pages/supplier/select" }); return; @@ -83,11 +87,19 @@ const _sfc_main = { goDetail() { this.activeTab = "detail"; try { - common_vendor.index.__f__("log", "at pages/index/index.vue:174", "[index] goDetail → /pages/detail/index"); + common_vendor.index.__f__("log", "at pages/index/index.vue:179", "[index] goDetail → /pages/detail/index"); } catch (e) { } common_vendor.index.navigateTo({ url: "/pages/detail/index" }); }, + goReport() { + this.activeTab = "report"; + common_vendor.index.navigateTo({ url: "/pages/report/entry" }); + }, + goMe() { + this.activeTab = "me"; + common_vendor.index.navigateTo({ url: "/pages/my/index" }); + }, onNoticeTap(n) { common_vendor.index.showModal({ title: "广告", @@ -148,9 +160,9 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { q: $data.activeTab === "detail" ? 1 : "", r: common_vendor.o((...args) => $options.goDetail && $options.goDetail(...args)), s: $data.activeTab === "report" ? 1 : "", - t: common_vendor.o(($event) => $data.activeTab = "report"), + t: common_vendor.o((...args) => $options.goReport && $options.goReport(...args)), v: $data.activeTab === "me" ? 1 : "", - w: common_vendor.o(($event) => $data.activeTab = "me") + w: common_vendor.o((...args) => $options.goMe && $options.goMe(...args)) }); } const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.js b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.js new file mode 100644 index 0000000..46081e9 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.js @@ -0,0 +1,27 @@ +"use strict"; +const common_vendor = require("../../common/vendor.js"); +const common_assets = require("../../common/assets.js"); +const _sfc_main = { + methods: { + openPolicy() { + common_vendor.index.showModal({ title: "隐私协议", content: "隐私协议(静态占位)", showCancel: false }); + }, + openTerms() { + common_vendor.index.showModal({ title: "用户协议", content: "用户协议(静态占位)", showCancel: false }); + }, + openComplaint() { + common_vendor.index.showToast({ title: "暂未开通", icon: "none" }); + } + } +}; +function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return { + a: common_assets._imports_0$1, + b: common_vendor.o((...args) => $options.openPolicy && $options.openPolicy(...args)), + c: common_vendor.o((...args) => $options.openTerms && $options.openTerms(...args)), + d: common_vendor.o((...args) => $options.openComplaint && $options.openComplaint(...args)) + }; +} +const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); +wx.createPage(MiniProgramPage); +//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/my/about.js.map diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.json b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.json new file mode 100644 index 0000000..35f68da --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "关于与协议", + "usingComponents": {} +} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.wxml new file mode 100644 index 0000000..7f668f3 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.wxml @@ -0,0 +1 @@ +五金配件管家专注小微门店的极简进销存版本1.0.0隐私协议查看用户协议查看个人信息安全投诉提交 \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.wxss new file mode 100644 index 0000000..3a61e38 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/about.wxss @@ -0,0 +1,21 @@ + +.about { padding: 24rpx; +} +.hero { padding: 32rpx 24rpx; display: flex; flex-direction: column; align-items: center; gap: 10rpx; +} +.logo { width: 160rpx; height: 160rpx; border-radius: 32rpx; +} +.title { margin-top: 8rpx; font-size: 36rpx; font-weight: 800; color: #333; +} +.subtitle { font-size: 26rpx; color: #888; +} +.card { margin-top: 18rpx; background: #fff; border-radius: 16rpx; overflow: hidden; +} +.row { display: flex; align-items: center; padding: 24rpx; border-top: 1rpx solid #f2f2f2; +} +.label { color: #666; +} +.value { margin-left: auto; color: #333; +} +.link { margin-left: auto; color: #1aad19; +} diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.js b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.js new file mode 100644 index 0000000..a666702 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.js @@ -0,0 +1,110 @@ +"use strict"; +const common_vendor = require("../../common/vendor.js"); +const common_http = require("../../common/http.js"); +const _sfc_main = { + data() { + return { + avatarUrl: "/static/logo.png", + shopName: "我的店铺", + mobile: "" + }; + }, + onLoad() { + this.fetchProfile(); + }, + computed: { + mobileDisplay() { + const m = String(this.mobile || ""); + return m.length === 11 ? m.slice(0, 3) + "****" + m.slice(7) : m || "未绑定手机号"; + } + }, + methods: { + async fetchProfile() { + try { + await common_http.get("/api/dashboard/overview"); + } catch (e) { + } + try { + const storeName = common_vendor.index.getStorageSync("SHOP_NAME") || ""; + const avatar = common_vendor.index.getStorageSync("USER_AVATAR") || ""; + const phone = common_vendor.index.getStorageSync("USER_MOBILE") || ""; + if (storeName) + this.shopName = storeName; + if (avatar) + this.avatarUrl = avatar; + this.mobile = phone; + } catch (e) { + } + }, + onAvatarError() { + this.avatarUrl = "/static/logo.png"; + }, + goVip() { + common_vendor.index.showToast({ title: "VIP会员(开发中)", icon: "none" }); + }, + goMyOrders() { + common_vendor.index.navigateTo({ url: "/pages/detail/index" }); + }, + goSupplier() { + common_vendor.index.navigateTo({ url: "/pages/supplier/select" }); + }, + goCustomer() { + common_vendor.index.navigateTo({ url: "/pages/customer/select" }); + }, + goCustomerQuote() { + common_vendor.index.showToast({ title: "客户报价(开发中)", icon: "none" }); + }, + goShop() { + common_vendor.index.showToast({ title: "店铺管理(开发中)", icon: "none" }); + }, + editProfile() { + common_vendor.index.showToast({ title: "账号与安全(开发中)", icon: "none" }); + }, + goProductSettings() { + common_vendor.index.navigateTo({ url: "/pages/product/settings" }); + }, + goSystemParams() { + common_vendor.index.showToast({ title: "系统参数(开发中)", icon: "none" }); + }, + goAbout() { + common_vendor.index.navigateTo({ url: "/pages/my/about" }); + }, + logout() { + try { + common_vendor.index.removeStorageSync("TOKEN"); + common_vendor.index.removeStorageSync("USER_AVATAR"); + common_vendor.index.removeStorageSync("USER_NAME"); + common_vendor.index.removeStorageSync("USER_MOBILE"); + common_vendor.index.removeStorageSync("SHOP_NAME"); + common_vendor.index.showToast({ title: "已退出", icon: "none" }); + setTimeout(() => { + common_vendor.index.reLaunch({ url: "/pages/index/index" }); + }, 300); + } catch (e) { + common_vendor.index.reLaunch({ url: "/pages/index/index" }); + } + } + } +}; +function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return { + a: $data.avatarUrl, + b: common_vendor.o((...args) => $options.onAvatarError && $options.onAvatarError(...args)), + c: common_vendor.t($data.shopName), + d: common_vendor.t($options.mobileDisplay), + e: common_vendor.o((...args) => $options.goVip && $options.goVip(...args)), + f: common_vendor.o((...args) => $options.goMyOrders && $options.goMyOrders(...args)), + g: common_vendor.o((...args) => $options.goSupplier && $options.goSupplier(...args)), + h: common_vendor.o((...args) => $options.goCustomer && $options.goCustomer(...args)), + i: common_vendor.o((...args) => $options.goCustomerQuote && $options.goCustomerQuote(...args)), + j: common_vendor.o((...args) => $options.goShop && $options.goShop(...args)), + k: common_vendor.o((...args) => $options.editProfile && $options.editProfile(...args)), + l: common_vendor.o((...args) => $options.goProductSettings && $options.goProductSettings(...args)), + m: common_vendor.o((...args) => $options.goSystemParams && $options.goSystemParams(...args)), + n: common_vendor.o((...args) => $options.goAbout && $options.goAbout(...args)), + o: common_vendor.o((...args) => $options.logout && $options.logout(...args)) + }; +} +const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); +wx.createPage(MiniProgramPage); +//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/my/index.js.map diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.json b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.json new file mode 100644 index 0000000..c0a8251 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "我的", + "usingComponents": {} +} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.wxml new file mode 100644 index 0000000..1a7c303 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.wxml @@ -0,0 +1 @@ +{{c}}{{d}}老板会员与订单VIP会员我的订单基础管理供应商管理客户管理客户报价店铺管理设置中心账号与安全修改头像、姓名、密码商品设置系统参数低价提示、默认收款、单行折扣等关于与协议退出登录 \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.wxss new file mode 100644 index 0000000..11176a2 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/my/index.wxss @@ -0,0 +1,27 @@ + +.me { padding: 24rpx; +} +.card.user { display: flex; gap: 18rpx; padding: 22rpx; background: #fff; border-radius: 16rpx; box-shadow: 0 6rpx 16rpx rgba(0,0,0,0.06); align-items: center; +} +.avatar { width: 120rpx; height: 120rpx; border-radius: 60rpx; background: #f5f5f5; +} +.meta { display: flex; flex-direction: column; gap: 6rpx; +} +.name { font-size: 34rpx; font-weight: 700; color: #333; +} +.phone { font-size: 26rpx; color: #888; +} +.role { font-size: 22rpx; color: #999; +} +.group { margin-top: 24rpx; background: #fff; border-radius: 16rpx; overflow: hidden; +} +.group-title { padding: 18rpx 22rpx; font-size: 26rpx; color: #999; background: #fafafa; +} +.cell { display: flex; align-items: center; padding: 26rpx 22rpx; border-top: 1rpx solid #f0f0f0; color: #333; +} +.cell .desc { margin-left: auto; margin-right: 8rpx; font-size: 22rpx; color: #999; +} +.cell .arrow { margin-left: auto; color: #bbb; +} +.cell.danger { color: #dd524d; justify-content: center; font-weight: 700; +} diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.js b/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.js index aef56d5..238ca47 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.js +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.js @@ -28,6 +28,7 @@ const _sfc_main = { supplierName: "", items: [], activeCategory: "sale_income", + counterpartyType: "customer", trxAmount: 0, selectedAccountId: null, selectedAccountName: "", @@ -50,16 +51,16 @@ const _sfc_main = { return this.supplierName || "零散供应商"; }, incomeCategories() { - return common_constants.INCOME_CATEGORIES; + return this._incomeCategories || common_constants.INCOME_CATEGORIES; }, expenseCategories() { - return common_constants.EXPENSE_CATEGORIES; + return this._expenseCategories || common_constants.EXPENSE_CATEGORIES; }, accountLabel() { return this.selectedAccountName || "现金"; }, counterpartyLabel() { - return this.customerName || this.supplierName || "—"; + return this.counterpartyType === "customer" ? this.customerName || "—" : this.supplierName || "—"; }, // 收款/付款合计 payTotal() { @@ -67,6 +68,9 @@ const _sfc_main = { return Number(p.cash || 0) + Number(p.bank || 0) + Number(p.wechat || 0); } }, + onLoad() { + this.fetchCategories(); + }, onShow() { if (this.biz === "sale") { if (this.order.customerId && this.order.customerId !== this._lastCustomerId) { @@ -85,6 +89,26 @@ const _sfc_main = { } }, methods: { + async fetchCategories() { + try { + const res = await common_http.get("/api/finance/categories"); + if (res && Array.isArray(res.incomeCategories)) + this._incomeCategories = res.incomeCategories; + if (res && Array.isArray(res.expenseCategories)) + this._expenseCategories = res.expenseCategories; + this.ensureActiveCategory(); + } catch (_) { + this.ensureActiveCategory(); + } + }, + ensureActiveCategory() { + const list = this.biz === "income" ? this.incomeCategories || [] : this.expenseCategories || []; + if (!list.length) + return; + const exists = list.some((it) => it && it.key === this.activeCategory); + if (!exists) + this.activeCategory = list[0].key; + }, async loadCustomerLevel(customerId) { try { const d = await common_http.get(`/api/customers/${customerId}`); @@ -133,6 +157,7 @@ const _sfc_main = { }, switchBiz(type) { this.biz = type; + this.ensureActiveCategory(); }, onDateChange(e) { this.order.orderTime = e.detail.value; @@ -147,13 +172,21 @@ const _sfc_main = { common_vendor.index.navigateTo({ url: "/pages/product/select" }); }, chooseAccount() { - common_vendor.index.navigateTo({ url: "/pages/account/select" }); + common_vendor.index.navigateTo({ url: "/pages/account/select?mode=pick" }); }, chooseCounterparty() { - if (this.biz === "income" || this.biz === "expense") { + if (!(this.biz === "income" || this.biz === "expense")) + return; + if (this.counterpartyType === "customer") { common_vendor.index.navigateTo({ url: "/pages/customer/select" }); + } else { + common_vendor.index.navigateTo({ url: "/pages/supplier/select" }); } }, + setCounterparty(t) { + this.counterpartyType = t; + this.ensureActiveCategory(); + }, recalc() { this.$forceUpdate(); }, @@ -189,7 +222,8 @@ const _sfc_main = { } : { type: this.biz, category: this.activeCategory, - counterpartyId: this.order.customerId || null, + counterpartyType: this.counterpartyType, + counterpartyId: this.counterpartyType === "customer" ? this.order.customerId || null : this.order.supplierId || null, accountId: this.selectedAccountId || null, amount: Number(this.trxAmount || 0), txTime: this.order.orderTime, @@ -288,7 +322,11 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { ac: common_vendor.t($options.totalAmount.toFixed(2)), ad: common_vendor.o((...args) => $options.chooseProduct && $options.chooseProduct(...args)) } : { - ae: common_vendor.f($data.biz === "income" ? $options.incomeCategories : $options.expenseCategories, (c, k0, i0) => { + ae: $data.counterpartyType === "customer" ? 1 : "", + af: common_vendor.o(($event) => $options.setCounterparty("customer")), + ag: $data.counterpartyType === "supplier" ? 1 : "", + ah: common_vendor.o(($event) => $options.setCounterparty("supplier")), + ai: common_vendor.f($data.biz === "income" ? $options.incomeCategories : $options.expenseCategories, (c, k0, i0) => { return { a: common_vendor.t(c.label), b: c.key, @@ -296,23 +334,23 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { d: common_vendor.o(($event) => $data.activeCategory = c.key, c.key) }; }), - af: common_vendor.t($options.counterpartyLabel), - ag: common_vendor.o((...args) => $options.chooseCounterparty && $options.chooseCounterparty(...args)), - ah: common_vendor.t($options.accountLabel), - ai: common_vendor.o((...args) => $options.chooseAccount && $options.chooseAccount(...args)), - aj: $data.trxAmount, - ak: common_vendor.o(common_vendor.m(($event) => $data.trxAmount = $event.detail.value, { + aj: common_vendor.t($options.counterpartyLabel), + ak: common_vendor.o((...args) => $options.chooseCounterparty && $options.chooseCounterparty(...args)), + al: common_vendor.t($options.accountLabel), + am: common_vendor.o((...args) => $options.chooseAccount && $options.chooseAccount(...args)), + an: $data.trxAmount, + ao: common_vendor.o(common_vendor.m(($event) => $data.trxAmount = $event.detail.value, { number: true })), - al: $data.order.remark, - am: common_vendor.o(($event) => $data.order.remark = $event.detail.value) + ap: $data.order.remark, + aq: common_vendor.o(($event) => $data.order.remark = $event.detail.value) }, { aa: $data.biz === "sale" || $data.biz === "purchase", - an: !$data.items.length + ar: !$data.items.length }, !$data.items.length ? { - ao: common_assets._imports_0$1 + as: common_assets._imports_0$1 } : { - ap: common_vendor.f($data.items, (it, idx, i0) => { + at: common_vendor.f($data.items, (it, idx, i0) => { return { a: common_vendor.t(it.productName), b: common_vendor.o([common_vendor.m(($event) => it.quantity = $event.detail.value, { @@ -328,8 +366,8 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { }; }) }, { - aq: common_vendor.o((...args) => $options.saveAndReset && $options.saveAndReset(...args)), - ar: common_vendor.o((...args) => $options.submit && $options.submit(...args)) + av: common_vendor.o((...args) => $options.saveAndReset && $options.saveAndReset(...args)), + aw: common_vendor.o((...args) => $options.submit && $options.submit(...args)) }); } const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxml index feec67e..636ee44 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxml +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxml @@ -1 +1 @@ -销售进货其他收入其他支出时间{{x}}客户{{B}}供应商{{E}}客户{{I}}供应商{{K}}现金银行存款微信{{S}}总金额:{{U}}{{X}}选中货品({{ab}})合计金额:¥ {{ac}}+{{c.a}}往来单位{{af}}结算账户{{ah}}金额购物车里空空如也扫描或点击 “+” 选择商品吧{{it.a}}¥ {{it.f}} \ No newline at end of file +销售进货其他收入其他支出时间{{x}}客户{{B}}供应商{{E}}客户{{I}}供应商{{K}}现金银行存款微信{{S}}总金额:{{U}}{{X}}选中货品({{ab}})合计金额:¥ {{ac}}+{{c.a}}往来单位{{aj}}结算账户{{al}}金额购物车里空空如也扫描或点击 “+” 选择商品吧{{it.a}}¥ {{it.f}} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxss index b24a832..6ed4946 100644 --- a/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxss +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/order/create.wxss @@ -49,4 +49,11 @@ .amount-badge { position: absolute; right: 24rpx; top: -36rpx; background: #d1f0ff; color:#107e9b; padding: 8rpx 16rpx; border-radius: 12rpx; font-size: 24rpx; } .date-mini { position: absolute; right: 24rpx; bottom: 20rpx; color:#666; font-size: 24rpx; +} + /* 分类chips样式:选中后文字变红 */ +.chips { display:flex; flex-wrap: wrap; gap: 12rpx; padding: 12rpx 24rpx; +} +.chip { padding: 10rpx 20rpx; border-radius: 999rpx; background: #f4f4f4; color:#666; +} +.chip.active { color: #e54d42; } diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.js b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.js new file mode 100644 index 0000000..dbb0a59 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.js @@ -0,0 +1,25 @@ +"use strict"; +const common_vendor = require("../../common/vendor.js"); +const _sfc_main = { + methods: { + go(mode, dim) { + const q = `mode=${encodeURIComponent(mode)}&dim=${encodeURIComponent(dim || "")}`; + common_vendor.index.navigateTo({ url: `/pages/report/index?${q}` }); + } + } +}; +function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return { + a: common_vendor.o(($event) => $options.go("sale", "customer")), + b: common_vendor.o(($event) => $options.go("sale", "product")), + c: common_vendor.o(($event) => $options.go("sale", "customer")), + d: common_vendor.o(($event) => $options.go("sale", "customer")), + e: common_vendor.o(($event) => $options.go("purchase", "supplier")), + f: common_vendor.o(($event) => $options.go("inventory", "qty")), + g: common_vendor.o(($event) => $options.go("arap", "ar")), + h: common_vendor.o(($event) => $options.go("arap", "ap")) + }; +} +const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); +wx.createPage(MiniProgramPage); +//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/report/entry.js.map diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.json b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.json new file mode 100644 index 0000000..a73dd63 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "报表", + "usingComponents": {} +} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.wxml new file mode 100644 index 0000000..aed737e --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.wxml @@ -0,0 +1 @@ +资金报表利润统计营业员统计经营业绩进销存报表销售统计进货统计库存统计应收对账单应付对账单 \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.wxss new file mode 100644 index 0000000..4a077a2 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/entry.wxss @@ -0,0 +1,13 @@ + +.entry { padding: 20rpx; +} +.section { margin-bottom: 24rpx; +} +.section-title { background:#f1f4f8; color:#6a7a8a; padding: 14rpx 16rpx; border-radius: 12rpx; font-weight: 700; +} +.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18rpx; padding: 18rpx 6rpx 0; +} +.btn { text-align: center; padding: 18rpx 8rpx; border: 1rpx solid #e5e9ef; border-radius: 12rpx; color:#333; background: #fff; +} +.btn:active { background: #f6f8fa; +} diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.js b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.js new file mode 100644 index 0000000..c0b711c --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.js @@ -0,0 +1,338 @@ +"use strict"; +const common_vendor = require("../../common/vendor.js"); +const common_http = require("../../common/http.js"); +function formatDate(d) { + const y = d.getFullYear(); + const m = String(d.getMonth() + 1).padStart(2, "0"); + const day = String(d.getDate()).padStart(2, "0"); + return `${y}-${m}-${day}`; +} +const _sfc_main = { + data() { + const now = /* @__PURE__ */ new Date(); + const start = new Date(now.getFullYear(), now.getMonth(), 1); + return { + startDate: formatDate(start), + endDate: formatDate(now), + mode: "sale", + dim: "customer", + rows: [], + total: { sales: 0, cost: 0, profit: 0 } + }; + }, + onLoad(query) { + try { + const m = query && query.mode; + const d = query && query.dim; + if (m) + this.mode = m; + if (d) + this.dim = d; + } catch (e) { + } + this.refresh(); + }, + computed: { + profitRate() { + const { sales, profit } = this.total; + if (!sales) + return "0.00%"; + return (profit / sales * 100).toFixed(2) + "%"; + } + }, + methods: { + fmt(n) { + return Number(n || 0).toFixed(2); + }, + setMode(m) { + this.mode = m; + this.dim = m === "sale" ? "customer" : m === "purchase" ? "supplier" : m === "inventory" ? "qty" : "ar"; + this.refresh(); + }, + onStartChange(e) { + this.startDate = e.detail.value; + this.refresh(); + }, + onEndChange(e) { + this.endDate = e.detail.value; + this.refresh(); + }, + async refresh() { + if (this.mode === "sale") { + if (this.dim === "customer") + return this.loadByCustomer(); + if (this.dim === "product") + return this.loadByProduct(); + } + if (this.mode === "purchase") { + if (this.dim === "supplier") + return this.loadPurchaseBySupplier(); + if (this.dim === "product") + return this.loadPurchaseByProduct(); + } + if (this.mode === "inventory") { + if (this.dim === "qty") + return this.loadInventoryByQty(); + if (this.dim === "amount") + return this.loadInventoryByAmount(); + } + if (this.mode === "arap") { + if (this.dim === "ar") + return this.loadAR(); + if (this.dim === "ap") + return this.loadAP(); + } + }, + async loadByCustomer() { + try { + const listResp = await common_http.get("/api/orders", { biz: "sale", type: "out", startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); + const list = listResp && (listResp.list || listResp) || []; + const map = /* @__PURE__ */ new Map(); + let totalSales = 0; + for (const it of list) { + const name = it.customerName || "未知客户"; + const amount = Number(it.amount || 0); + totalSales += amount; + if (!map.has(name)) + map.set(name, { name, sales: 0, cost: 0, profit: 0 }); + const row = map.get(name); + row.sales += amount; + } + const rows = Array.from(map.values()).map((r) => ({ ...r, profit: r.sales - r.cost })); + const total = { sales: totalSales, cost: 0, profit: totalSales }; + this.rows = rows; + this.total = total; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + async loadByProduct() { + try { + const listResp = await common_http.get("/api/orders", { biz: "sale", type: "out", startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); + const list = listResp && (listResp.list || listResp) || []; + const agg = /* @__PURE__ */ new Map(); + for (const it of list) { + try { + const d = await common_http.get(`/api/orders/${it.id}`); + const items = d && d.items || []; + for (const m of items) { + const key = String(m.productId || m.name); + if (!agg.has(key)) + agg.set(key, { name: m.name || "#" + key, sales: 0, cost: 0, profit: 0 }); + const row = agg.get(key); + const sales = Number(m.amount || 0); + row.sales += sales; + } + } catch (_) { + } + } + const rows = Array.from(agg.values()).map((r) => ({ ...r, profit: r.sales - r.cost })); + const totalSales = rows.reduce((s, r) => s + r.sales, 0); + this.rows = rows; + this.total = { sales: totalSales, cost: 0, profit: totalSales }; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + async loadPurchaseBySupplier() { + try { + const listResp = await common_http.get("/api/purchase-orders", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); + const list = listResp && (listResp.list || listResp) || []; + const map = /* @__PURE__ */ new Map(); + let total = 0; + for (const it of list) { + const name = it.supplierName || "未知供应商"; + const amount = Number(it.amount || 0); + total += amount; + if (!map.has(name)) + map.set(name, { name, sales: 0, cost: 0, profit: 0 }); + const row = map.get(name); + row.sales += amount; + } + this.rows = Array.from(map.values()); + this.total = { sales: total, cost: 0, profit: 0 }; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + async loadPurchaseByProduct() { + try { + const listResp = await common_http.get("/api/purchase-orders", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); + const list = listResp && (listResp.list || listResp) || []; + const agg = /* @__PURE__ */ new Map(); + for (const it of list) { + try { + const d = await common_http.get(`/api/purchase-orders/${it.id}`); + for (const m of (d == null ? void 0 : d.items) || []) { + const key = String(m.productId || m.name); + if (!agg.has(key)) + agg.set(key, { name: m.name || "#" + key, sales: 0, cost: 0, profit: 0 }); + const row = agg.get(key); + row.sales += Number(m.amount || 0); + } + } catch (_) { + } + } + const rows = Array.from(agg.values()); + const total = rows.reduce((s, r) => s + r.sales, 0); + this.rows = rows; + this.total = { sales: total, cost: 0, profit: 0 }; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + async loadInventoryByQty() { + try { + const resp = await common_http.get("/api/inventories/logs", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); + const list = resp && (resp.list || resp) || []; + const map = /* @__PURE__ */ new Map(); + let totalQty = 0; + for (const it of list) { + const key = it.productId || "未知"; + if (!map.has(key)) + map.set(key, { name: String(key), sales: 0, cost: 0, profit: 0 }); + const row = map.get(key); + const q = Number(it.qtyDelta || 0); + row.sales += q; + totalQty += q; + } + this.rows = Array.from(map.values()); + this.total = { sales: totalQty, cost: 0, profit: 0 }; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + async loadInventoryByAmount() { + try { + const resp = await common_http.get("/api/inventories/logs", { startDate: this.startDate, endDate: this.endDate, page: 1, size: 200 }); + const list = resp && (resp.list || resp) || []; + const map = /* @__PURE__ */ new Map(); + let totalAmt = 0; + for (const it of list) { + const key = it.productId || "未知"; + if (!map.has(key)) + map.set(key, { name: String(key), sales: 0, cost: 0, profit: 0 }); + const row = map.get(key); + const a = Number(it.amount || it.amountDelta || 0); + row.sales += a; + totalAmt += a; + } + this.rows = Array.from(map.values()); + this.total = { sales: totalAmt, cost: 0, profit: 0 }; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + async loadAR() { + try { + const res = await common_http.get("/api/customers", { page: 1, size: 100, debtOnly: false }); + const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; + const rows = list.map((c) => ({ name: c.name, sales: Number(c.receivable || 0), cost: 0, profit: 0 })); + const total = rows.reduce((s, r) => s + r.sales, 0); + this.rows = rows; + this.total = { sales: total, cost: 0, profit: 0 }; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + }, + async loadAP() { + try { + const res = await common_http.get("/api/suppliers", { page: 1, size: 100 }); + const list = Array.isArray(res == null ? void 0 : res.list) ? res.list : Array.isArray(res) ? res : []; + const rows = list.map((s) => ({ name: s.name, sales: Number(s.apPayable || 0), cost: 0, profit: 0 })); + const total = rows.reduce((s, r) => s + r.sales, 0); + this.rows = rows; + this.total = { sales: total, cost: 0, profit: 0 }; + } catch (e) { + common_vendor.index.showToast({ title: "加载失败", icon: "none" }); + } + } + } +}; +function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { + return common_vendor.e({ + a: $data.mode === "sale" ? 1 : "", + b: common_vendor.o(($event) => $options.setMode("sale")), + c: $data.mode === "purchase" ? 1 : "", + d: common_vendor.o(($event) => $options.setMode("purchase")), + e: $data.mode === "inventory" ? 1 : "", + f: common_vendor.o(($event) => $options.setMode("inventory")), + g: $data.mode === "arap" ? 1 : "", + h: common_vendor.o(($event) => $options.setMode("arap")), + i: common_vendor.t($data.startDate), + j: $data.startDate, + k: common_vendor.o((...args) => $options.onStartChange && $options.onStartChange(...args)), + l: common_vendor.t($data.endDate), + m: $data.endDate, + n: common_vendor.o((...args) => $options.onEndChange && $options.onEndChange(...args)), + o: $data.mode === "sale" + }, $data.mode === "sale" ? { + p: $data.dim === "customer" ? 1 : "", + q: common_vendor.o(($event) => { + $data.dim = "customer"; + $options.refresh(); + }), + r: $data.dim === "product" ? 1 : "", + s: common_vendor.o(($event) => { + $data.dim = "product"; + $options.refresh(); + }) + } : $data.mode === "purchase" ? { + v: $data.dim === "supplier" ? 1 : "", + w: common_vendor.o(($event) => { + $data.dim = "supplier"; + $options.refresh(); + }), + x: $data.dim === "product" ? 1 : "", + y: common_vendor.o(($event) => { + $data.dim = "product"; + $options.refresh(); + }) + } : $data.mode === "inventory" ? { + A: $data.dim === "qty" ? 1 : "", + B: common_vendor.o(($event) => { + $data.dim = "qty"; + $options.refresh(); + }), + C: $data.dim === "amount" ? 1 : "", + D: common_vendor.o(($event) => { + $data.dim = "amount"; + $options.refresh(); + }) + } : $data.mode === "arap" ? { + F: $data.dim === "ar" ? 1 : "", + G: common_vendor.o(($event) => { + $data.dim = "ar"; + $options.refresh(); + }), + H: $data.dim === "ap" ? 1 : "", + I: common_vendor.o(($event) => { + $data.dim = "ap"; + $options.refresh(); + }) + } : {}, { + t: $data.mode === "purchase", + z: $data.mode === "inventory", + E: $data.mode === "arap", + J: common_vendor.t($options.fmt($data.total.sales)), + K: common_vendor.t($options.fmt($data.total.cost)), + L: common_vendor.t($options.fmt($data.total.profit)), + M: common_vendor.t($options.profitRate), + N: common_vendor.f($data.rows, (row, idx, i0) => { + return common_vendor.e({ + a: row.avatar + }, row.avatar ? { + b: row.avatar + } : {}, { + c: common_vendor.t(row.name), + d: common_vendor.t($options.fmt(row.sales)), + e: common_vendor.t($options.fmt(row.cost)), + f: common_vendor.t($options.fmt(row.profit)), + g: idx + }); + }) + }); +} +const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); +wx.createPage(MiniProgramPage); +//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/report/index.js.map diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.json b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.json new file mode 100644 index 0000000..a73dd63 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "报表", + "usingComponents": {} +} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.wxml b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.wxml new file mode 100644 index 0000000..9bd9131 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.wxml @@ -0,0 +1 @@ +销售统计进货统计库存统计应收/应付对账{{i}}{{l}}按客户按货品按供应商按货品按数量按金额应收对账应付对账销售额¥ {{J}}成本¥ {{K}}利润¥ {{L}}利润率{{M}}{{row.c}}销售额:¥ {{row.d}}成本:¥ {{row.e}}利润:¥ {{row.f}} \ No newline at end of file diff --git a/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.wxss b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.wxss new file mode 100644 index 0000000..ddb3617 --- /dev/null +++ b/frontend/unpackage/dist/dev/mp-weixin/pages/report/index.wxss @@ -0,0 +1,37 @@ + +.report { padding: 20rpx; +} +.modes { display: flex; gap: 12rpx; margin-bottom: 14rpx; +} +.mode-tab { flex: 1; text-align: center; padding: 16rpx 0; border-radius: 999rpx; background: #f4f4f4; color: #666; border: 1rpx solid #e9e9e9; +} +.mode-tab.active { background: #1aad19; color: #fff; border-color: #1aad19; font-weight: 700; +} +.toolbar { display: flex; align-items: center; gap: 8rpx; background: #fff; padding: 14rpx 16rpx; border-radius: 12rpx; +} +.date { padding: 10rpx 16rpx; border: 1rpx solid #eee; border-radius: 8rpx; +} +.tabs { display: flex; gap: 16rpx; margin-top: 14rpx; +} +.tab { padding: 12rpx 18rpx; border-radius: 999rpx; background: #f4f4f4; color: #666; +} +.tab.active { background: #1aad19; color: #fff; +} +.summary { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8rpx; margin-top: 14rpx; +} +.summary .item { background: #fff; border-radius: 12rpx; padding: 16rpx; +} +.summary .label { font-size: 22rpx; color: #888; +} +.summary .value { display: block; margin-top: 8rpx; font-weight: 700; color: #333; +} +.card { margin-top: 16rpx; background: #fff; border-radius: 12rpx; padding: 16rpx; +} +.row-head { display: flex; align-items: center; gap: 12rpx; +} +.thumb { width: 72rpx; height: 72rpx; border-radius: 8rpx; background: #f2f2f2; +} +.title { font-size: 28rpx; font-weight: 700; +} +.row-body { margin-top: 10rpx; color: #666; +} diff --git a/沟通.md b/沟通.md index 8de017e..adba160 100644 --- a/沟通.md +++ b/沟通.md @@ -12,25 +12,31 @@ 前端:1.货品功能√ 后端:1.首页核心数据√ 2.所有图片用占位图backend\picture代替 - 3.货品功能√(还有问题) 9.18王德鹏1: 前端:1.明细功能√ 后端:1.数据库驱动改为硬编码 2.货品功能√ - 3.开单(未全完成) 9.18王德鹏2: 前端:1.客户功能√ -后端:1.客户功能√(未全完成) 数据库:1.客户表更改 9.18王德鹏3: 前端:1.供应商功能√ 后端:1.客户功能√ - 2.供应商功能√ + 2.供应商功能√v 3.开单功能(销售进货)√ +9.20王德鹏1: +前端:1.账户功能√ + 2.我的功能√ + 3.报表功能√ +后端:1.账户功能√ + 2.开单功能√ + 3.明细功能√ + 4.报表功能√ +