From 7b9187fb6246abfc170022214f6fded8a50c4279 Mon Sep 17 00:00:00 2001 From: zhenhui <1276357500@qq.com> Date: Tue, 21 Apr 2026 14:30:15 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=96=B0=E5=A2=9E=E9=A9=AC=E6=9D=A5=E8=AF=AD?= =?UTF-8?q?ms=EF=BC=8C=E4=BF=AE=E6=94=B9=E6=9C=89=E5=95=86=E5=93=81?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=92=8C=E6=89=80=E6=9C=89=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/controller/mall/Item.php | 131 ++++++++++++++++ app/api/controller/v1/Playx.php | 98 +++++++++++- app/api/lang/en.php | 140 +++++++++++------- app/api/lang/ms.php | 88 +++++++++++ app/common/middleware/LoadLangPack.php | 8 +- app/common/model/MallItem.php | 7 + config/lang.php | 2 +- web/src/lang/backend/en/mall/item.ts | 4 + web/src/lang/backend/zh-cn/mall/item.ts | 4 + web/src/views/backend/mall/item/index.vue | 44 ++++++ web/src/views/backend/mall/item/popupForm.vue | 34 +++++ 11 files changed, 501 insertions(+), 59 deletions(-) create mode 100644 app/api/lang/ms.php diff --git a/app/admin/controller/mall/Item.php b/app/admin/controller/mall/Item.php index 4a475a8..970959d 100644 --- a/app/admin/controller/mall/Item.php +++ b/app/admin/controller/mall/Item.php @@ -87,4 +87,135 @@ class Item extends Backend 'remark' => get_route_remark(), ]); } + + /** + * 兼容不同前端键名,避免英文字段被漏存。 + * - 优先 snake_case: title_en / description_en + * - 回落 camelCase: titleEn / descriptionEn + */ + private function normalizeLangFields(array $data): array + { + $data['title_en'] = isset($data['title_en']) + ? strval($data['title_en']) + : strval($data['titleEn'] ?? ''); + $data['description_en'] = isset($data['description_en']) + ? strval($data['description_en']) + : strval($data['descriptionEn'] ?? ''); + $data['title_ms'] = isset($data['title_ms']) + ? strval($data['title_ms']) + : strval($data['titleMs'] ?? ''); + $data['description_ms'] = isset($data['description_ms']) + ? strval($data['description_ms']) + : strval($data['descriptionMs'] ?? ''); + + unset($data['titleEn'], $data['descriptionEn'], $data['titleMs'], $data['descriptionMs']); + + return $data; + } + + /** + * 重写新增:显式处理中英马三语字段。 + */ + protected function _add(): Response + { + if ($this->request && $this->request->method() === 'POST') { + $data = $this->request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->applyInputFilter($data); + $data = $this->normalizeLangFields($data); + $data = $this->excludeFields($data); + if ($this->dataLimit && $this->dataLimitFieldAutoFill) { + $data[$this->dataLimitField] = $this->auth->id; + } + if ($this->autoFillAdminId && $this->dataLimitField === 'admin_id') { + $data['admin_id'] = $this->auth->id; + } + + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) { + $validate->scene('add'); + } + $validate->check($data); + } + } + $result = $this->model->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Added successfully')); + } + return $this->error(__('No rows were added')); + } + + return $this->error(__('Parameter error')); + } + + /** + * 重写编辑:显式处理中英马三语字段。 + */ + protected function _edit(): Response + { + $pk = $this->model->getPk(); + $id = $this->request ? ($this->request->post($pk) ?? $this->request->get($pk)) : null; + $row = $this->model->find($id); + if (!$row) { + return $this->error(__('Record not found')); + } + + $dataLimitAdminIds = $this->getDataLimitAdminIds(); + if ($dataLimitAdminIds && !in_array($row[$this->dataLimitField], $dataLimitAdminIds)) { + return $this->error(__('You have no permission')); + } + + if ($this->request && $this->request->method() === 'POST') { + $data = $this->request->post(); + if (!$data) { + return $this->error(__('Parameter %s can not be empty', [''])); + } + + $data = $this->applyInputFilter($data); + $data = $this->normalizeLangFields($data); + $data = $this->excludeFields($data); + $result = false; + $this->model->startTrans(); + try { + if ($this->modelValidate) { + $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model)); + if (class_exists($validate)) { + $validate = new $validate(); + if ($this->modelSceneValidate) { + $validate->scene('edit'); + } + $data[$pk] = $row[$pk]; + $validate->check($data); + } + } + $result = $row->save($data); + $this->model->commit(); + } catch (Throwable $e) { + $this->model->rollback(); + return $this->error($e->getMessage()); + } + if ($result !== false) { + return $this->success(__('Update successful')); + } + return $this->error(__('No rows updated')); + } + + return $this->success('', [ + 'row' => $row + ]); + } } \ No newline at end of file diff --git a/app/api/controller/v1/Playx.php b/app/api/controller/v1/Playx.php index a12f157..672f2b3 100644 --- a/app/api/controller/v1/Playx.php +++ b/app/api/controller/v1/Playx.php @@ -620,7 +620,12 @@ class Playx extends Api } $list = $query->order('sort', 'asc')->select(); - return $this->success('', ['list' => $list->toArray()]); + $out = []; + foreach ($list->toArray() as $row) { + $out[] = $this->applyMallItemLocaleForApi($row); + } + + return $this->success('', ['list' => $out]); } /** @@ -676,7 +681,15 @@ class Playx extends Api ->limit(100) ->select(); - return $this->success('', ['list' => $list->toArray()]); + $arr = $list->toArray(); + foreach ($arr as &$orderRow) { + if (isset($orderRow['mallItem']) && is_array($orderRow['mallItem'])) { + $orderRow['mallItem'] = $this->applyMallItemLocaleForApi($orderRow['mallItem']); + } + } + unset($orderRow); + + return $this->success('', ['list' => $arr]); } /** @@ -877,6 +890,18 @@ SQL; } } + $itemsMap = $this->buildMallItemLocaleMapForPointsLog($list); + foreach ($list as &$row) { + $id = (int)($row['item_id'] ?? 0); + if ($id > 0 && isset($itemsMap[$id])) { + $row['item_title'] = $itemsMap[$id]['title']; + if (isset($row['mallItem']) && is_array($row['mallItem'])) { + $row['mallItem']['title'] = $itemsMap[$id]['title']; + } + } + } + unset($row); + return $this->success('', [ 'list' => $list, 'next_cursor' => $nextCursor, @@ -1306,6 +1331,75 @@ SQL; ]); } + private function getApiLocale(): string + { + if (function_exists('locale')) { + $l = locale(); + if (is_string($l) && $l !== '') { + return $l; + } + } + + return 'zh-cn'; + } + + /** + * @param array $item MallItem 行(可含 title_en/title_ms 与 description_en/description_ms) + * @return array + */ + private function applyMallItemLocaleForApi(array $item): array + { + $lang = $this->getApiLocale(); + if ($lang === 'en') { + $te = trim((string)($item['title_en'] ?? '')); + $de = trim((string)($item['description_en'] ?? '')); + if ($te !== '') { + $item['title'] = $te; + } + if ($de !== '') { + $item['description'] = $de; + } + } elseif ($lang === 'ms') { + $tm = trim((string)($item['title_ms'] ?? '')); + $dm = trim((string)($item['description_ms'] ?? '')); + if ($tm !== '') { + $item['title'] = $tm; + } + if ($dm !== '') { + $item['description'] = $dm; + } + } + unset($item['title_en'], $item['description_en'], $item['title_ms'], $item['description_ms']); + + return $item; + } + + /** + * @param list> $list pointsLogs 已组装的列表 + * @return array> id => item 行(已本地化并去掉 *_ms) + */ + private function buildMallItemLocaleMapForPointsLog(array $list): array + { + $ids = []; + foreach ($list as $row) { + $id = (int)($row['item_id'] ?? 0); + if ($id > 0) { + $ids[$id] = true; + } + } + if ($ids === []) { + return []; + } + $idList = array_keys($ids); + $map = []; + $models = MallItem::whereIn('id', $idList)->select(); + foreach ($models as $model) { + $map[intval($model->id)] = $this->applyMallItemLocaleForApi($model->toArray()); + } + + return $map; + } + private function callPlayxBonusGrant(MallOrder $order, MallItem $item, string $userId): void { $baseUrl = rtrim(config('playx.api.base_url', ''), '/'); diff --git a/app/api/lang/en.php b/app/api/lang/en.php index d335411..4306b3e 100644 --- a/app/api/lang/en.php +++ b/app/api/lang/en.php @@ -1,57 +1,87 @@ 'Login expired, please login again.', - 'Account not exist' => 'Account does not exist', - 'Account disabled' => 'Account is disabled', - 'Token login failed' => 'Token login failed', - 'Please try again after 1 day' => 'The number of failed login attempts has exceeded the limit, please try again after 24 hours.', - 'Password is incorrect' => 'Incorrect password', - 'You are not logged in' => 'You are not logged in.', - 'Unknown operation' => 'Unknown operation', - 'No action available, please contact the administrator~' => 'There is no action available, please contact the administrator~', - 'Please login first' => 'Please login first!', - 'You have no permission' => 'No permission to operate!', - 'Captcha error' => 'Captcha error!', - 'Parameter %s can not be empty' => 'Parameter %s can not be empty', - 'Parameter signature/secret/agent_id/time can not be empty' => 'Parameter signature/secret/agent_id/time can not be empty', - 'Invalid timestamp' => 'Invalid timestamp', - 'Timestamp expired' => 'Timestamp expired', - 'Invalid agent or secret' => 'Invalid agent or secret', - 'Invalid signature' => 'Invalid signature', - 'Agent not found' => 'Agent not found', - 'Temp login is disabled' => 'Temp login is disabled', - 'Failed to create temp account' => 'Failed to allocate a unique phone number, please retry later', - 'Parameter username can not be empty' => 'Parameter username can not be empty', - 'Token expiration' => 'Session expired, please login again.', - // Member center account - 'Data updated successfully~' => 'Data updated successfully~', - 'Password has been changed~' => 'Password has been changed~', - 'Password has been changed, please login again~' => 'Password has been changed, please login again~', - 'already exists' => 'already exists', - 'nicknameChsDash' => 'Usernames can only be Chinese characters, letters, numbers, underscores_ and dashes-.', - // PlayX API v1 /api/v1/* - 'Invalid token' => 'Invalid or expired token', - 'PlayX API not configured' => 'PlayX API is not configured', - 'Duplicate input' => 'Duplicate submission', - 'Ok' => 'OK', - 'Failed to map playx user to mall user' => 'Failed to map PlayX user to mall user', - 'Missing required fields: request_id, date, user_id' => 'Missing required fields: request_id, date, user_id', - 'Missing required fields: report_date, member' => 'Missing required fields: report_date, member', - 'Missing required fields: member_id' => 'Missing required fields: member_id', - 'Daily push signature missing or incomplete' => 'Daily push signature missing or incomplete', - 'Daily push signature verification failed' => 'Daily push signature verification failed', - 'Failed to ensure PlayX user asset' => 'Failed to ensure PlayX user asset', - 'claim_request_id and user_id/session_id required' => 'claim_request_id and user_id/session_id/token are required', - 'User asset not found' => 'User asset not found', - 'No points to claim or limit reached' => 'No points to claim or daily limit reached', - 'Claim success' => 'Claim successful', - 'item_id and user_id/session_id required' => 'item_id and user_id/session_id/token are required', - 'Item not found or not available' => 'Item not found or not available', - 'Insufficient points' => 'Insufficient points', - 'Redeem submitted, please wait about 10 minutes' => 'Redeem submitted, please wait about 10 minutes', - 'Missing required fields' => 'Missing required fields', - 'Shipping address not found' => 'Shipping address not found', - 'Out of stock' => 'Out of stock', - 'Redeem success' => 'Redeem successful', - 'Withdraw submitted, please wait about 10 minutes' => 'Withdrawal submitted, please wait about 10 minutes', -]; \ No newline at end of file + '%d second%s ago' => '%d second%s ago', + '%d minute%s ago' => '%d minute%s ago', + '%d hour%s ago' => '%d hour%s ago', + '%d day%s ago' => '%d day%s ago', + '%d week%s ago' => '%d week%s ago', + '%d month%s ago' => '%d month%s ago', + '%d year%s ago' => '%d year%s ago', + '%d second%s after' => '%d second%s later', + '%d minute%s after' => '%d minute%s later', + '%d hour%s after' => '%d hour%s later', + '%d day%s after' => '%d day%s later', + '%d week%s after' => '%d week%s later', + '%d month%s after' => '%d month%s later', + '%d year%s after' => '%d year%s later', + 'File uploaded successfully' => 'File uploaded successfully!', + 'No files were uploaded' => 'No files were uploaded', + 'The uploaded file format is not allowed' => 'The uploaded file format is not allowed', + 'The uploaded image file is not a valid image' => 'The uploaded image is not valid', + 'The uploaded file is too large (%sMiB), Maximum file size:%sMiB' => 'The file is too large (%sMiB), maximum: %sMiB', + 'No files have been uploaded or the file size exceeds the upload limit of the server' => 'No file uploaded or size exceeds server limit', + 'Topic format error' => 'Storage topic format error', + 'Driver %s not supported' => 'Driver not supported: %s', + 'Username' => 'Username', + 'Email' => 'Email', + 'Mobile' => 'Mobile', + 'Password' => 'Password', + 'Login expired, please login again.' => 'Login expired, please login again.', + 'Account not exist' => 'Account does not exist', + 'Account disabled' => 'Account is disabled', + 'Token login failed' => 'Token login failed', + 'Please try again after 1 day' => 'Too many failed attempts, please try again after 24 hours', + 'Password is incorrect' => 'Incorrect password', + 'You are not logged in' => 'You are not logged in', + 'Unknown operation' => 'Unknown operation', + 'No action available, please contact the administrator~' => 'No action available, please contact the administrator~', + 'Please login first' => 'Please login first!', + 'You have no permission' => 'No permission!', + 'Parameter error' => 'Parameter error!', + 'Parameter %s can not be empty' => 'Parameter %s cannot be empty', + 'Parameter signature/secret/agent_id/time can not be empty' => 'Parameter signature/secret/agent_id/time cannot be empty', + 'Invalid timestamp' => 'Invalid timestamp', + 'Timestamp expired' => 'Timestamp expired', + 'Invalid agent or secret' => 'Invalid agent or secret', + 'Invalid signature' => 'Invalid signature', + 'Agent not found' => 'Agent not found', + 'Temp login is disabled' => 'Temporary login is disabled', + 'Failed to create temp account' => 'Failed to create temporary account, please retry', + 'Parameter username can not be empty' => 'Parameter username cannot be empty', + 'Token expiration' => 'Session expired, please login again.', + 'Captcha error' => 'Captcha error!', + 'Data updated successfully~' => 'Profile updated successfully~', + 'Password has been changed~' => 'Password has been changed~', + 'Password has been changed, please login again~' => 'Password changed, please login again~', + 'already exists' => 'already exists', + 'nicknameChsDash' => 'Username may only contain letters, numbers, underscores and dashes', + 'Invalid token' => 'Invalid or expired token', + 'PlayX API not configured' => 'PlayX API is not configured', + 'Duplicate input' => 'Duplicate submission', + 'Ok' => 'OK', + 'Failed to map playx user to mall user' => 'Failed to map PlayX user to mall user', + 'Missing required fields: request_id, date, user_id' => 'Missing required fields: request_id, date, user_id', + 'Missing required fields: report_date, member' => 'Missing required fields: report_date, member', + 'Missing required fields: member_id' => 'Missing required fields: member_id', + 'Daily push signature missing or incomplete' => 'Daily push signature missing or incomplete', + 'Daily push signature verification failed' => 'Daily push signature verification failed', + 'Failed to ensure PlayX user asset' => 'Failed to ensure PlayX user asset', + 'claim_request_id and user_id/session_id required' => 'claim_request_id and user_id/session_id/token are required', + 'User asset not found' => 'User asset not found', + 'No points to claim or limit reached' => 'No points to claim or daily limit reached', + 'Claim success' => 'Claim successful', + 'item_id and user_id/session_id required' => 'item_id and user_id/session_id/token are required', + 'Item not found or not available' => 'Item not found or not available', + 'Insufficient points' => 'Insufficient points', + 'Redeem submitted, please wait about 10 minutes' => 'Redeem submitted, please wait about 10 minutes', + 'Missing required fields' => 'Missing required fields', + 'Out of stock' => 'Out of stock', + 'Record not found' => 'Record not found', + 'Shipping address not found' => 'Shipping address not found', + 'Redeem success' => 'Redeem successful', + 'Withdraw submitted, please wait about 10 minutes' => 'Withdrawal submitted, please wait about 10 minutes', +]; diff --git a/app/api/lang/ms.php b/app/api/lang/ms.php new file mode 100644 index 0000000..b809494 --- /dev/null +++ b/app/api/lang/ms.php @@ -0,0 +1,88 @@ + '%d saat yang lalu', + '%d minute%s ago' => '%d minit yang lalu', + '%d hour%s ago' => '%d jam yang lalu', + '%d day%s ago' => '%d hari yang lalu', + '%d week%s ago' => '%d minggu yang lalu', + '%d month%s ago' => '%d bulan yang lalu', + '%d year%s ago' => '%d tahun yang lalu', + '%d second%s after' => '%d saat lagi', + '%d minute%s after' => '%d minit lagi', + '%d hour%s after' => '%d jam lagi', + '%d day%s after' => '%d hari lagi', + '%d week%s after' => '%d minggu lagi', + '%d month%s after' => '%d bulan lagi', + '%d year%s after' => '%d tahun lagi', + 'File uploaded successfully' => 'Fail berjaya dimuat naik!', + 'No files were uploaded' => 'Tiada fail dimuat naik', + 'The uploaded file format is not allowed' => 'Format fail yang dimuat naik tidak dibenarkan', + 'The uploaded image file is not a valid image' => 'Fail imej yang dimuat naik tidak sah', + 'The uploaded file is too large (%sMiB), Maximum file size:%sMiB' => 'Fail terlalu besar (%sM), saiz maksimum: %sM', + 'No files have been uploaded or the file size exceeds the upload limit of the server' => 'Tiada fail dimuat naik atau saiz melebihi had pelayan', + 'Topic format error' => 'Ralat format topik storan', + 'Driver %s not supported' => 'Pemandu tidak disokong: %s', + 'Username' => 'Nama pengguna', + 'Email' => 'E-mel', + 'Mobile' => 'Telefon bimbit', + 'Password' => 'Kata laluan', + 'Login expired, please login again.' => 'Log masuk tamat tempoh, sila log masuk semula.', + 'Account not exist' => 'Akaun tidak wujud', + 'Account disabled' => 'Akaun dilumpuhkan', + 'Token login failed' => 'Log masuk token gagal', + 'Please try again after 1 day' => 'Percubaan gagal terlalu kerap, sila cuba semula selepas 1 hari', + 'Password is incorrect' => 'Kata laluan tidak betul', + 'You are not logged in' => 'Anda belum log masuk', + 'Unknown operation' => 'Operasi tidak diketahui', + 'No action available, please contact the administrator~' => 'Tiada tindakan tersedia, sila hubungi pentadbir~', + 'Please login first' => 'Sila log masuk dahulu!', + 'You have no permission' => 'Tiada kebenaran!', + 'Parameter error' => 'Ralat parameter!', + 'Parameter %s can not be empty' => 'Parameter %s tidak boleh kosong', + 'Parameter signature/secret/agent_id/time can not be empty' => 'Parameter signature/secret/agent_id/time tidak boleh kosong', + 'Invalid timestamp' => 'Cap masa tidak sah', + 'Timestamp expired' => 'Cap masa tamat tempoh', + 'Invalid agent or secret' => 'Ejen atau rahsia tidak sah', + 'Invalid signature' => 'Tandatangan tidak sah', + 'Agent not found' => 'Ejen tidak dijumpai', + 'Temp login is disabled' => 'Log masuk sementara dilumpuhkan', + 'Failed to create temp account' => 'Gagal mencipta akaun sementara, sila cuba lagi', + 'Parameter username can not be empty' => 'Parameter username tidak boleh kosong', + 'Token expiration' => 'Sesi tamat, sila log masuk semula!', + 'Captcha error' => 'Ralat captcha!', + 'Data updated successfully~' => 'Data berjaya dikemas kini~', + 'Password has been changed~' => 'Kata laluan telah ditukar~', + 'Password has been changed, please login again~' => 'Kata laluan ditukar, sila log masuk semula~', + 'already exists' => 'sudah wujud', + 'nicknameChsDash' => 'Nama pengguna hanya huruf, nombor, garis bawah dan sempang', + 'Invalid token' => 'Token tidak sah atau tamat tempoh', + 'PlayX API not configured' => 'API PlayX tidak dikonfigurasi', + 'Duplicate input' => 'Penghantaran pendua', + 'Ok' => 'OK', + 'Failed to map playx user to mall user' => 'Gagal memetakan pengguna PlayX ke pengguna mall', + 'Missing required fields: request_id, date, user_id' => 'Medan wajib tiada: request_id, date, user_id', + 'Missing required fields: report_date, member' => 'Medan wajib tiada: report_date, member', + 'Missing required fields: member_id' => 'Medan wajib tiada: member_id', + 'Daily push signature missing or incomplete' => 'Tandatangan push harian tiada atau tidak lengkap', + 'Daily push signature verification failed' => 'Pengesahan tandatangan push harian gagal', + 'Failed to ensure PlayX user asset' => 'Gagal mencipta/memeta aset pengguna', + 'claim_request_id and user_id/session_id required' => 'claim_request_id dan user_id/session_id/token diperlukan', + 'User asset not found' => 'Aset pengguna tidak dijumpai', + 'No points to claim or limit reached' => 'Tiada mata untuk dituntut atau had harian dicapai', + 'Claim success' => 'Tuntutan berjaya', + 'item_id and user_id/session_id required' => 'item_id dan user_id/session_id/token diperlukan', + 'Item not found or not available' => 'Item tidak dijumpai atau tidak tersedia', + 'Insufficient points' => 'Mata tidak mencukupi', + 'Redeem submitted, please wait about 10 minutes' => 'Penebusan dihantar, sila tunggu kira-kira 10 minit', + 'Missing required fields' => 'Medan wajib tiada', + 'Out of stock' => 'Stok tidak mencukupi', + 'Record not found' => 'Rekod tidak dijumpai', + 'Shipping address not found' => 'Alamat penghantaran tidak dijumpai', + 'Redeem success' => 'Penebusan berjaya', + 'Withdraw submitted, please wait about 10 minutes' => 'Permohonan pengeluaran dihantar, sila tunggu kira-kira 10 minit', +]; diff --git a/app/common/middleware/LoadLangPack.php b/app/common/middleware/LoadLangPack.php index 70a479a..2bd91d2 100644 --- a/app/common/middleware/LoadLangPack.php +++ b/app/common/middleware/LoadLangPack.php @@ -12,7 +12,7 @@ use Webman\Http\Response; * 加载控制器语言包中间件(Webman 迁移版,等价 ThinkPHP LoadLangPack) * 根据当前路由加载对应控制器的语言包到 Translator * - * 对外 api/:优先请求头 lang(zh / zh-cn → 中文包 zh-cn,en → 英文包),未传则 think-lang,再默认 zh-cn(不根据浏览器 Accept-Language) + * 对外 api/:优先请求头 lang(zh / zh-cn → zh-cn,en → en,ms → 马来语包),未传则 think-lang,再默认 zh-cn(不根据浏览器 Accept-Language) * admin/:think-lang → Accept-Language → 配置默认 */ class LoadLangPack implements MiddlewareInterface @@ -138,6 +138,12 @@ class LoadLangPack implements MiddlewareInterface if (str_starts_with($s, 'en')) { return in_array('en', $allowLangList, true) ? 'en' : null; } + if ($s === 'ms' || str_starts_with($s, 'ms-')) { + return in_array('ms', $allowLangList, true) ? 'ms' : null; + } + if ($s === 'may') { + return in_array('ms', $allowLangList, true) ? 'ms' : null; + } if ($s === 'zh' || str_starts_with($s, 'zh-')) { return in_array('zh-cn', $allowLangList, true) ? 'zh-cn' : null; } diff --git a/app/common/model/MallItem.php b/app/common/model/MallItem.php index 787de73..e57c376 100644 --- a/app/common/model/MallItem.php +++ b/app/common/model/MallItem.php @@ -7,6 +7,13 @@ use support\think\Model; /** * MallItem * type: 1=BONUS(红利), 2=PHYSICAL(实物), 3=WITHDRAW(提现档位) + * + * @property string $title + * @property string $description + * @property string $title_en + * @property string|null $description_en + * @property string $title_ms + * @property string|null $description_ms */ class MallItem extends Model { diff --git a/config/lang.php b/config/lang.php index 4a22961..0ac5cce 100644 --- a/config/lang.php +++ b/config/lang.php @@ -4,5 +4,5 @@ */ return [ 'default_lang' => env('LANG_DEFAULT_LANG', 'zh-cn'), - 'allow_lang_list' => ['zh-cn', 'en'], + 'allow_lang_list' => ['zh-cn', 'en', 'ms'], ]; diff --git a/web/src/lang/backend/en/mall/item.ts b/web/src/lang/backend/en/mall/item.ts index 0b67133..388c358 100644 --- a/web/src/lang/backend/en/mall/item.ts +++ b/web/src/lang/backend/en/mall/item.ts @@ -2,6 +2,10 @@ export default { id: 'ID', title: 'Title', description: 'Description', + title_en: 'Title (English)', + description_en: 'Description (English)', + title_ms: 'Title (Malay)', + description_ms: 'Description (Malay)', remark: 'Remark', score: 'Points', type: 'Type', diff --git a/web/src/lang/backend/zh-cn/mall/item.ts b/web/src/lang/backend/zh-cn/mall/item.ts index fe6539d..ccdcbd5 100644 --- a/web/src/lang/backend/zh-cn/mall/item.ts +++ b/web/src/lang/backend/zh-cn/mall/item.ts @@ -2,6 +2,10 @@ export default { id: 'ID', title: '标题', description: '描述', + title_en: '标题(英文)', + description_en: '描述(英文)', + title_ms: '标题(马来语)', + description_ms: '描述(马来语)', remark: '备注', score: '兑换积分', type: '类型', diff --git a/web/src/views/backend/mall/item/index.vue b/web/src/views/backend/mall/item/index.vue index 00c21b4..0065e7f 100644 --- a/web/src/views/backend/mall/item/index.vue +++ b/web/src/views/backend/mall/item/index.vue @@ -58,6 +58,46 @@ const baTable = new baTableClass( sortable: false, operator: 'LIKE', }, + { + label: t('mall.item.title_en'), + prop: 'title_en', + align: 'center', + minWidth: 90, + show: false, + operatorPlaceholder: t('Fuzzy query'), + sortable: false, + operator: 'LIKE', + }, + { + label: t('mall.item.description_en'), + prop: 'description_en', + align: 'center', + minWidth: 90, + show: false, + operatorPlaceholder: t('Fuzzy query'), + sortable: false, + operator: 'LIKE', + }, + { + label: t('mall.item.title_ms'), + prop: 'title_ms', + align: 'center', + minWidth: 90, + show: false, + operatorPlaceholder: t('Fuzzy query'), + sortable: false, + operator: 'LIKE', + }, + { + label: t('mall.item.description_ms'), + prop: 'description_ms', + align: 'center', + minWidth: 90, + show: false, + operatorPlaceholder: t('Fuzzy query'), + sortable: false, + operator: 'LIKE', + }, { label: t('mall.item.score'), prop: 'score', @@ -189,6 +229,10 @@ const baTable = new baTableClass( defaultItems: { stock: 0, sort: 100, + title_en: '', + description_en: '', + title_ms: '', + description_ms: '', }, } ) diff --git a/web/src/views/backend/mall/item/popupForm.vue b/web/src/views/backend/mall/item/popupForm.vue index ddb1a50..0a7ee9f 100644 --- a/web/src/views/backend/mall/item/popupForm.vue +++ b/web/src/views/backend/mall/item/popupForm.vue @@ -57,6 +57,40 @@ @keyup.ctrl.enter="baTable.onSubmit(formRef)" :placeholder="t('Please input field', { field: t('mall.item.description') })" /> + + + +