refactor(classes): organize inc/classes into domain folders
Move ~94 root class shells and root *-traits into domain directories (core, auth, user, credits, content, payment/gateways, forum, shop, sms, ai, messages, extensions, widgets, settings, admin). Update bootstrap require paths, co-locate traits with owners, fix forum/user relative requires, drop duplicate shop controller requires, and wire home-modules load. Path-only; class names and init order unchanged.
This commit is contained in:
1 parent
2a8fe68048
commit
ce1c13b947
115 files changed
+171
-224
No files matched your search
@@ -0,0 +1,365 @@
|
||||
<?php
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait AKSRT_Shipping_Part_1 {
|
||||
|
||||
private function send_shipping_notification(string $order_number, string $carrier, string $tracking_no, string $note = ''): void {
|
||||
if (!class_exists('AKSRT_Order_Repository')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order = AKSRT_Order_Repository::get_instance()->get($order_number);
|
||||
if (!$order) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user_id = (int) ($order['user_id'] ?? 0);
|
||||
if ($user_id <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user || empty($user->user_email)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$carrier_label = $this->get_carrier_label($carrier);
|
||||
$site_name = get_bloginfo('name');
|
||||
$subject = sprintf(__('[%s] 您的订单已发货', 'aksrt'), $site_name);
|
||||
$body = sprintf(
|
||||
__('您好 %1$s,\n\n您的订单 %2$s 已发货。\n\n物流公司:%3$s\n运单号:%4$s\n%5$s\n\n如有疑问请联系客服。\n\n%s', 'aksrt'),
|
||||
$user->display_name,
|
||||
$order_number,
|
||||
$carrier_label,
|
||||
$tracking_no,
|
||||
$note !== '' ? sprintf(__('备注:%s', 'aksrt'), $note) : '',
|
||||
$site_name
|
||||
);
|
||||
|
||||
wp_mail($user->user_email, $subject, $body);
|
||||
}
|
||||
|
||||
private function decorate_record(array $record): array {
|
||||
$record['id'] = (int) ($record['id'] ?? 0);
|
||||
$record['operator_id'] = isset($record['operator_id']) ? (int) $record['operator_id'] : 0;
|
||||
$record['status_label'] = $this->get_status_label((string) ($record['status'] ?? ''));
|
||||
$record['carrier_label'] = $this->get_carrier_label((string) ($record['carrier'] ?? ''));
|
||||
$record['operator'] = $this->get_user_summary((int) ($record['operator_id'] ?? 0));
|
||||
return $record;
|
||||
}
|
||||
|
||||
private function get_carrier_label(string $carrier): string {
|
||||
foreach (self::get_carrier_options() as $item) {
|
||||
if (($item['value'] ?? '') === $carrier) {
|
||||
return (string) ($item['label'] ?? $carrier);
|
||||
}
|
||||
}
|
||||
|
||||
return $carrier;
|
||||
}
|
||||
|
||||
private function get_status_label(string $status): string {
|
||||
foreach (self::get_status_options() as $item) {
|
||||
if (($item['value'] ?? '') === $status) {
|
||||
return (string) ($item['label'] ?? $status);
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
private function get_user_summary(int $user_id): array {
|
||||
if ($user_id <= 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$user = get_userdata($user_id);
|
||||
if (!$user) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $user_id,
|
||||
'display_name' => (string) $user->display_name,
|
||||
'user_login' => (string) $user->user_login,
|
||||
];
|
||||
}
|
||||
|
||||
private function build_summary_item(array $record): array {
|
||||
return [
|
||||
'id' => (int) ($record['id'] ?? 0),
|
||||
'status' => (string) ($record['status'] ?? ''),
|
||||
'status_label' => (string) ($record['status_label'] ?? ''),
|
||||
'carrier' => (string) ($record['carrier'] ?? ''),
|
||||
'carrier_label' => (string) ($record['carrier_label'] ?? ''),
|
||||
'tracking_no' => (string) ($record['tracking_no'] ?? ''),
|
||||
'created_at' => (string) ($record['created_at'] ?? ''),
|
||||
'updated_at' => (string) ($record['updated_at'] ?? ''),
|
||||
'delivered_at' => (string) ($record['delivered_at'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
private function can_transition_status(string $current_status, string $new_status): bool {
|
||||
$map = [
|
||||
self::STATUS_SHIPPED => [self::STATUS_IN_TRANSIT, self::STATUS_DELIVERED, self::STATUS_RETURNED],
|
||||
self::STATUS_IN_TRANSIT => [self::STATUS_DELIVERED, self::STATUS_RETURNED],
|
||||
self::STATUS_DELIVERED => [],
|
||||
self::STATUS_RETURNED => [],
|
||||
];
|
||||
|
||||
return in_array($new_status, $map[$current_status] ?? [], true);
|
||||
}
|
||||
|
||||
private function sync_order_status(string $order_number, string $shipping_status, string $note = ''): void {
|
||||
if ($order_number === '' || !class_exists('AKSRT_Order_Repository') || !class_exists('AKSRT_Order')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($shipping_status, [self::STATUS_SHIPPED, self::STATUS_IN_TRANSIT, self::STATUS_DELIVERED], true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AKSRT_Order_Repository::get_instance()->update_status($order_number, AKSRT_Order::STATUS_DELIVERED, [
|
||||
'note' => $note,
|
||||
]);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Express Query API (§6.6 快递查询)
|
||||
*
|
||||
* Supports kuaidi100, aliyun, kdniao.
|
||||
* Traces cached in order_shipping.express_data JSON.
|
||||
* Refresh interval from shop settings.
|
||||
* ============================================================ */
|
||||
|
||||
public function query_express(int $shipping_id, bool $force = false): array {
|
||||
global $wpdb;
|
||||
$record = $this->get($shipping_id);
|
||||
if (!$record) {
|
||||
return ['success' => false, 'message' => __('发货记录不存在', 'aksrt')];
|
||||
}
|
||||
|
||||
$tracking_no = (string) ($record['tracking_no'] ?? '');
|
||||
$carrier = (string) ($record['carrier'] ?? '');
|
||||
if ($tracking_no === '' || $carrier === '') {
|
||||
return ['success' => false, 'message' => __('缺少运单号或物流公司', 'aksrt')];
|
||||
}
|
||||
|
||||
$cached = $this->get_express_cache($shipping_id);
|
||||
if (!$force && !empty($cached) && !$this->should_refresh_cache($cached)) {
|
||||
return ['success' => true, 'data' => $cached];
|
||||
}
|
||||
|
||||
if (!empty($cached['signed'])) {
|
||||
return ['success' => true, 'data' => $cached];
|
||||
}
|
||||
|
||||
$shop_settings = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_shop_settings() : [];
|
||||
$api_sdk = sanitize_key((string) ($shop_settings['express']['api_sdk'] ?? 'kuaidi100'));
|
||||
|
||||
$result = $this->call_express_api($api_sdk, $carrier, $tracking_no, $shop_settings);
|
||||
|
||||
if ($result['success']) {
|
||||
$express_data = [
|
||||
'query_time' => current_time('mysql'),
|
||||
'traces' => $result['traces'] ?? [],
|
||||
'state' => $result['state'] ?? 'unknown',
|
||||
'signed' => !empty($result['signed']),
|
||||
'api' => $api_sdk,
|
||||
];
|
||||
|
||||
$wpdb->update(
|
||||
$this->table(),
|
||||
['note' => wp_json_encode($express_data, JSON_UNESCAPED_UNICODE)],
|
||||
['id' => $shipping_id],
|
||||
['%s'],
|
||||
['%d']
|
||||
);
|
||||
|
||||
if (!empty($result['signed']) && ($record['status'] ?? '') !== self::STATUS_DELIVERED) {
|
||||
$this->update_status($shipping_id, self::STATUS_DELIVERED, __('快递已签收(API检测)', 'aksrt'));
|
||||
}
|
||||
|
||||
return ['success' => true, 'data' => $express_data];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function get_express_cache(int $shipping_id): array {
|
||||
global $wpdb;
|
||||
$note = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT note FROM {$this->table()} WHERE id = %d",
|
||||
$shipping_id
|
||||
));
|
||||
if (!$note) return [];
|
||||
$data = json_decode($note, true);
|
||||
return is_array($data) && isset($data['traces']) ? $data : [];
|
||||
}
|
||||
|
||||
private function should_refresh_cache(array $cached): bool {
|
||||
if (empty($cached['query_time'])) return true;
|
||||
|
||||
$shop = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_shop_settings() : [];
|
||||
$interval = max(30, min(240, (int) ($shop['express']['query_interval'] ?? 60)));
|
||||
|
||||
$last = strtotime($cached['query_time']);
|
||||
return (time() - $last) > ($interval * 60);
|
||||
}
|
||||
|
||||
private function call_express_api(string $sdk, string $carrier, string $tracking_no, array $settings): array {
|
||||
$carrier_code = $this->map_carrier_code($sdk, $carrier);
|
||||
|
||||
if ($sdk === 'kuaidi100') {
|
||||
return $this->query_kuaidi100($carrier_code, $tracking_no, $settings);
|
||||
}
|
||||
if ($sdk === 'kdniao') {
|
||||
return $this->query_kdniao($carrier_code, $tracking_no, $settings);
|
||||
}
|
||||
if ($sdk === 'aliyun') {
|
||||
return $this->query_aliyun($carrier_code, $tracking_no, $settings);
|
||||
}
|
||||
|
||||
return ['success' => false, 'message' => __('未配置快递查询接口', 'aksrt')];
|
||||
}
|
||||
|
||||
private function query_kuaidi100(string $com, string $num, array $settings): array {
|
||||
$key = sanitize_text_field((string) ($settings['express']['kuaidi100_key'] ?? ''));
|
||||
$customer = sanitize_text_field((string) ($settings['express']['kuaidi100_customer'] ?? ''));
|
||||
if ($key === '' || $customer === '') {
|
||||
return ['success' => false, 'message' => __('快递100 API 未配置', 'aksrt')];
|
||||
}
|
||||
|
||||
$param = wp_json_encode(['com' => $com, 'num' => $num]);
|
||||
$sign = strtoupper(md5($param . $key . $customer));
|
||||
|
||||
$response = wp_remote_post('https://poll.kuaidi100.com/poll/query.do', [
|
||||
'body' => ['customer' => $customer, 'sign' => $sign, 'param' => $param],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return ['success' => false, 'message' => $response->get_error_message()];
|
||||
}
|
||||
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
if (!is_array($body) || (int) ($body['status'] ?? 0) !== 200) {
|
||||
return ['success' => false, 'message' => (string) ($body['message'] ?? __('查询失败', 'aksrt'))];
|
||||
}
|
||||
|
||||
$state = (string) ($body['state'] ?? '0');
|
||||
$signed = $state === '3';
|
||||
|
||||
$traces = [];
|
||||
foreach ((array) ($body['data'] ?? []) as $item) {
|
||||
$traces[] = [
|
||||
'time' => (string) ($item['ftime'] ?? $item['time'] ?? ''),
|
||||
'context' => (string) ($item['context'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
return ['success' => true, 'traces' => $traces, 'state' => $state, 'signed' => $signed];
|
||||
}
|
||||
|
||||
private function query_kdniao(string $code, string $num, array $settings): array {
|
||||
$app_id = sanitize_text_field((string) ($settings['express']['kdniao_app_id'] ?? ''));
|
||||
$app_key = sanitize_text_field((string) ($settings['express']['kdniao_app_key'] ?? ''));
|
||||
if ($app_id === '' || $app_key === '') {
|
||||
return ['success' => false, 'message' => __('快递鸟 API 未配置', 'aksrt')];
|
||||
}
|
||||
|
||||
$request_data = wp_json_encode(['ShipperCode' => $code, 'LogisticCode' => $num]);
|
||||
$data_sign = urlencode(base64_encode(md5($request_data . $app_key)));
|
||||
|
||||
$response = wp_remote_post('https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx', [
|
||||
'body' => [
|
||||
'RequestData' => urlencode($request_data),
|
||||
'EBusinessID' => $app_id,
|
||||
'RequestType' => '1002',
|
||||
'DataSign' => $data_sign,
|
||||
'DataType' => '2',
|
||||
],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return ['success' => false, 'message' => $response->get_error_message()];
|
||||
}
|
||||
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
if (!is_array($body) || !($body['Success'] ?? false)) {
|
||||
return ['success' => false, 'message' => (string) ($body['Reason'] ?? __('查询失败', 'aksrt'))];
|
||||
}
|
||||
|
||||
$state = (string) ($body['State'] ?? '0');
|
||||
$signed = $state === '3';
|
||||
|
||||
$traces = [];
|
||||
foreach ((array) ($body['Traces'] ?? []) as $item) {
|
||||
$traces[] = [
|
||||
'time' => (string) ($item['AcceptTime'] ?? ''),
|
||||
'context' => (string) ($item['AcceptStation'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
return ['success' => true, 'traces' => $traces, 'state' => $state, 'signed' => $signed];
|
||||
}
|
||||
|
||||
private function query_aliyun(string $code, string $num, array $settings): array {
|
||||
$app_code = sanitize_text_field((string) ($settings['express']['aliyun_app_code'] ?? ''));
|
||||
if ($app_code === '') {
|
||||
return ['success' => false, 'message' => __('阿里云快递 API 未配置', 'aksrt')];
|
||||
}
|
||||
|
||||
$url = add_query_arg(['no' => $num, 'type' => $code], 'https://wuliu.market.alicloudapi.com/kdi');
|
||||
|
||||
$response = wp_remote_get($url, [
|
||||
'headers' => ['Authorization' => 'APPCODE ' . $app_code],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return ['success' => false, 'message' => $response->get_error_message()];
|
||||
}
|
||||
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
if (!is_array($body) || (int) ($body['status'] ?? -1) !== 0) {
|
||||
return ['success' => false, 'message' => (string) ($body['msg'] ?? __('查询失败', 'aksrt'))];
|
||||
}
|
||||
|
||||
$result_data = $body['result'] ?? [];
|
||||
$state = (string) ($result_data['deliverystatus'] ?? '0');
|
||||
$signed = $state === '3';
|
||||
|
||||
$traces = [];
|
||||
foreach ((array) ($result_data['list'] ?? []) as $item) {
|
||||
$traces[] = [
|
||||
'time' => (string) ($item['time'] ?? ''),
|
||||
'context' => (string) ($item['status'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
return ['success' => true, 'traces' => $traces, 'state' => $state, 'signed' => $signed];
|
||||
}
|
||||
|
||||
private function map_carrier_code(string $sdk, string $carrier): string {
|
||||
$kuaidi100_map = [
|
||||
'sf' => 'shunfeng', 'yd' => 'yunda', 'zt' => 'zhongtong', 'yt' => 'yuantong',
|
||||
'sto' => 'shentong', 'jd' => 'jd', 'ems' => 'ems', 'db' => 'debangkuaidi',
|
||||
'yunda' => 'yunda',
|
||||
];
|
||||
$kdniao_map = [
|
||||
'sf' => 'SF', 'yd' => 'YD', 'zt' => 'ZTO', 'yt' => 'YTO',
|
||||
'sto' => 'STO', 'jd' => 'JD', 'ems' => 'EMS', 'db' => 'DBL',
|
||||
'yunda' => 'YD',
|
||||
];
|
||||
|
||||
if ($sdk === 'kuaidi100') {
|
||||
return $kuaidi100_map[$carrier] ?? $carrier;
|
||||
}
|
||||
if ($sdk === 'kdniao') {
|
||||
return $kdniao_map[$carrier] ?? strtoupper($carrier);
|
||||
}
|
||||
return $carrier;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
trait AKSRT_Shipping_Part_2 {
|
||||
|
||||
|
||||
public function build_express_timeline(int $shipping_id): array {
|
||||
$record = $this->get($shipping_id);
|
||||
if (!$record) return [];
|
||||
|
||||
$cached = $this->get_express_cache($shipping_id);
|
||||
$timeline = [];
|
||||
|
||||
$timeline[] = [
|
||||
'time' => (string) ($record['created_at'] ?? ''),
|
||||
'label' => sprintf(__('商家已发货:%s %s', 'aksrt'), $record['carrier_label'] ?? '', $record['tracking_no'] ?? ''),
|
||||
'type' => 'shipped',
|
||||
];
|
||||
|
||||
if (!empty($cached['traces'])) {
|
||||
foreach ($cached['traces'] as $trace) {
|
||||
$timeline[] = [
|
||||
'time' => (string) ($trace['time'] ?? ''),
|
||||
'label' => (string) ($trace['context'] ?? ''),
|
||||
'type' => 'trace',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($cached['signed'])) {
|
||||
$timeline[] = [
|
||||
'time' => (string) ($record['delivered_at'] ?? ($cached['query_time'] ?? '')),
|
||||
'label' => __('快递已签收', 'aksrt'),
|
||||
'type' => 'signed',
|
||||
];
|
||||
}
|
||||
|
||||
usort($timeline, static fn($a, $b) => strcmp($a['time'] ?? '', $b['time'] ?? ''));
|
||||
return $timeline;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Shipping Fee Resolution (§6.6 运费模板)
|
||||
*
|
||||
* 3 types: free / fixed / amount (满额包邮)
|
||||
* Inheritance: product → category → theme defaults
|
||||
* ============================================================ */
|
||||
|
||||
public function resolve_shipping_fee(int $product_id, float $order_amount = 0, array $address = []): array {
|
||||
$config = $this->get_product_shipping_config($product_id);
|
||||
$fee_type = (string) ($config['fee_type'] ?? 'fixed');
|
||||
$fee_amount = (float) ($config['fee_amount'] ?? 0);
|
||||
$free_threshold = (float) ($config['free_threshold'] ?? 0);
|
||||
|
||||
if ($fee_type === 'free') {
|
||||
return ['fee' => 0.0, 'type' => 'free', 'label' => __('包邮', 'aksrt')];
|
||||
}
|
||||
|
||||
if ($fee_type === 'amount' && $free_threshold > 0 && $order_amount >= $free_threshold) {
|
||||
return ['fee' => 0.0, 'type' => 'free_threshold', 'label' => sprintf(__('满%.0f包邮', 'aksrt'), $free_threshold)];
|
||||
}
|
||||
|
||||
$region_fee = $this->resolve_region_fee($config, $address);
|
||||
if ($region_fee !== null) {
|
||||
return ['fee' => $region_fee, 'type' => 'region', 'label' => __('地区运费', 'aksrt')];
|
||||
}
|
||||
|
||||
return ['fee' => $fee_amount, 'type' => 'fixed', 'label' => sprintf(__('运费 ¥%.2f', 'aksrt'), $fee_amount)];
|
||||
}
|
||||
|
||||
private function get_product_shipping_config(int $product_id): array {
|
||||
$meta = get_post_meta($product_id, '_aksrt_shipping_config', true);
|
||||
if (is_array($meta) && !empty($meta['fee_type'])) {
|
||||
return $meta;
|
||||
}
|
||||
|
||||
if (class_exists('AKSRT_Shop_Term_Meta')) {
|
||||
$cat_config = AKSRT_Shop_Term_Meta::resolve_inheritance($product_id, 'shipping_fee');
|
||||
if (is_array($cat_config) && !empty($cat_config['fee_type'])) {
|
||||
return $cat_config;
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('AKSRT_Settings')) {
|
||||
$shop = AKSRT_Settings::get_shop_settings();
|
||||
return [
|
||||
'fee_type' => sanitize_key((string) ($shop['defaults']['shipping_fee_type'] ?? 'fixed')),
|
||||
'fee_amount' => (float) ($shop['defaults']['shipping_fee_amount'] ?? 12),
|
||||
'free_threshold' => (float) ($shop['defaults']['shipping_free_threshold'] ?? 0),
|
||||
'region_fees' => (array) ($shop['defaults']['region_fees'] ?? []),
|
||||
];
|
||||
}
|
||||
|
||||
return ['fee_type' => 'fixed', 'fee_amount' => 12, 'free_threshold' => 0, 'region_fees' => []];
|
||||
}
|
||||
|
||||
private function resolve_region_fee(array $config, array $address): ?float {
|
||||
$region_fees = (array) ($config['region_fees'] ?? []);
|
||||
if (empty($region_fees) || empty($address['province'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$province = (string) $address['province'];
|
||||
foreach ($region_fees as $region) {
|
||||
$provinces = (array) ($region['provinces'] ?? []);
|
||||
if (in_array($province, $provinces, true)) {
|
||||
return (float) ($region['fee'] ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function get_china_regions(): array {
|
||||
$file = get_template_directory() . '/assets/data/china-regions.json';
|
||||
if (!file_exists($file)) {
|
||||
return self::get_builtin_provinces();
|
||||
}
|
||||
$data = json_decode((string) file_get_contents($file), true);
|
||||
return is_array($data) ? $data : self::get_builtin_provinces();
|
||||
}
|
||||
|
||||
private static function get_builtin_provinces(): array {
|
||||
return [
|
||||
['code' => '11', 'name' => '北京市'], ['code' => '12', 'name' => '天津市'],
|
||||
['code' => '13', 'name' => '河北省'], ['code' => '14', 'name' => '山西省'],
|
||||
['code' => '15', 'name' => '内蒙古自治区'], ['code' => '21', 'name' => '辽宁省'],
|
||||
['code' => '22', 'name' => '吉林省'], ['code' => '23', 'name' => '黑龙江省'],
|
||||
['code' => '31', 'name' => '上海市'], ['code' => '32', 'name' => '江苏省'],
|
||||
['code' => '33', 'name' => '浙江省'], ['code' => '34', 'name' => '安徽省'],
|
||||
['code' => '35', 'name' => '福建省'], ['code' => '36', 'name' => '江西省'],
|
||||
['code' => '37', 'name' => '山东省'], ['code' => '41', 'name' => '河南省'],
|
||||
['code' => '42', 'name' => '湖北省'], ['code' => '43', 'name' => '湖南省'],
|
||||
['code' => '44', 'name' => '广东省'], ['code' => '45', 'name' => '广西壮族自治区'],
|
||||
['code' => '46', 'name' => '海南省'], ['code' => '50', 'name' => '重庆市'],
|
||||
['code' => '51', 'name' => '四川省'], ['code' => '52', 'name' => '贵州省'],
|
||||
['code' => '53', 'name' => '云南省'], ['code' => '54', 'name' => '西藏自治区'],
|
||||
['code' => '61', 'name' => '陕西省'], ['code' => '62', 'name' => '甘肃省'],
|
||||
['code' => '63', 'name' => '青海省'], ['code' => '64', 'name' => '宁夏回族自治区'],
|
||||
['code' => '65', 'name' => '新疆维吾尔自治区'],
|
||||
['code' => '71', 'name' => '台湾省'],
|
||||
['code' => '81', 'name' => '香港特别行政区'],
|
||||
['code' => '82', 'name' => '澳门特别行政区'],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user