chore: resolve conflicts
This commit is contained in:
commit
1e16ef3e0d
@ -121,7 +121,10 @@ func responseAli2OpenAI(response *AliChatResponse) *OpenAITextResponse {
|
|||||||
func streamResponseAli2OpenAI(aliResponse *AliChatResponse) *ChatCompletionsStreamResponse {
|
func streamResponseAli2OpenAI(aliResponse *AliChatResponse) *ChatCompletionsStreamResponse {
|
||||||
var choice ChatCompletionsStreamResponseChoice
|
var choice ChatCompletionsStreamResponseChoice
|
||||||
choice.Delta.Content = aliResponse.Output.Text
|
choice.Delta.Content = aliResponse.Output.Text
|
||||||
choice.FinishReason = aliResponse.Output.FinishReason
|
if aliResponse.Output.FinishReason != "null" {
|
||||||
|
finishReason := aliResponse.Output.FinishReason
|
||||||
|
choice.FinishReason = &finishReason
|
||||||
|
}
|
||||||
response := ChatCompletionsStreamResponse{
|
response := ChatCompletionsStreamResponse{
|
||||||
Id: aliResponse.RequestId,
|
Id: aliResponse.RequestId,
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
|
@ -120,7 +120,9 @@ func responseBaidu2OpenAI(response *BaiduChatResponse) *OpenAITextResponse {
|
|||||||
func streamResponseBaidu2OpenAI(baiduResponse *BaiduChatStreamResponse) *ChatCompletionsStreamResponse {
|
func streamResponseBaidu2OpenAI(baiduResponse *BaiduChatStreamResponse) *ChatCompletionsStreamResponse {
|
||||||
var choice ChatCompletionsStreamResponseChoice
|
var choice ChatCompletionsStreamResponseChoice
|
||||||
choice.Delta.Content = baiduResponse.Result
|
choice.Delta.Content = baiduResponse.Result
|
||||||
choice.FinishReason = "stop"
|
if baiduResponse.IsEnd {
|
||||||
|
choice.FinishReason = &stopFinishReason
|
||||||
|
}
|
||||||
response := ChatCompletionsStreamResponse{
|
response := ChatCompletionsStreamResponse{
|
||||||
Id: baiduResponse.Id,
|
Id: baiduResponse.Id,
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
|
@ -81,7 +81,10 @@ func requestOpenAI2Claude(textRequest GeneralOpenAIRequest) *ClaudeRequest {
|
|||||||
func streamResponseClaude2OpenAI(claudeResponse *ClaudeResponse) *ChatCompletionsStreamResponse {
|
func streamResponseClaude2OpenAI(claudeResponse *ClaudeResponse) *ChatCompletionsStreamResponse {
|
||||||
var choice ChatCompletionsStreamResponseChoice
|
var choice ChatCompletionsStreamResponseChoice
|
||||||
choice.Delta.Content = claudeResponse.Completion
|
choice.Delta.Content = claudeResponse.Completion
|
||||||
choice.FinishReason = stopReasonClaude2OpenAI(claudeResponse.StopReason)
|
finishReason := stopReasonClaude2OpenAI(claudeResponse.StopReason)
|
||||||
|
if finishReason != "null" {
|
||||||
|
choice.FinishReason = &finishReason
|
||||||
|
}
|
||||||
var response ChatCompletionsStreamResponse
|
var response ChatCompletionsStreamResponse
|
||||||
response.Object = "chat.completion.chunk"
|
response.Object = "chat.completion.chunk"
|
||||||
response.Model = claudeResponse.Model
|
response.Model = claudeResponse.Model
|
||||||
|
@ -94,7 +94,7 @@ func streamResponsePaLM2OpenAI(palmResponse *PaLMChatResponse) *ChatCompletionsS
|
|||||||
if len(palmResponse.Candidates) > 0 {
|
if len(palmResponse.Candidates) > 0 {
|
||||||
choice.Delta.Content = palmResponse.Candidates[0].Content
|
choice.Delta.Content = palmResponse.Candidates[0].Content
|
||||||
}
|
}
|
||||||
choice.FinishReason = "stop"
|
choice.FinishReason = &stopFinishReason
|
||||||
var response ChatCompletionsStreamResponse
|
var response ChatCompletionsStreamResponse
|
||||||
response.Object = "chat.completion.chunk"
|
response.Object = "chat.completion.chunk"
|
||||||
response.Model = "palm2"
|
response.Model = "palm2"
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"one-api/common"
|
"one-api/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var stopFinishReason = "stop"
|
||||||
|
|
||||||
var tokenEncoderMap = map[string]*tiktoken.Tiktoken{}
|
var tokenEncoderMap = map[string]*tiktoken.Tiktoken{}
|
||||||
|
|
||||||
func getTokenEncoder(model string) *tiktoken.Tiktoken {
|
func getTokenEncoder(model string) *tiktoken.Tiktoken {
|
||||||
|
@ -138,6 +138,9 @@ func streamResponseXunfei2OpenAI(xunfeiResponse *XunfeiChatResponse) *ChatComple
|
|||||||
}
|
}
|
||||||
var choice ChatCompletionsStreamResponseChoice
|
var choice ChatCompletionsStreamResponseChoice
|
||||||
choice.Delta.Content = xunfeiResponse.Payload.Choices.Text[0].Content
|
choice.Delta.Content = xunfeiResponse.Payload.Choices.Text[0].Content
|
||||||
|
if xunfeiResponse.Payload.Choices.Status == 2 {
|
||||||
|
choice.FinishReason = &stopFinishReason
|
||||||
|
}
|
||||||
response := ChatCompletionsStreamResponse{
|
response := ChatCompletionsStreamResponse{
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
Created: common.GetTimestamp(),
|
Created: common.GetTimestamp(),
|
||||||
|
@ -163,7 +163,6 @@ func responseZhipu2OpenAI(response *ZhipuResponse) *OpenAITextResponse {
|
|||||||
func streamResponseZhipu2OpenAI(zhipuResponse string) *ChatCompletionsStreamResponse {
|
func streamResponseZhipu2OpenAI(zhipuResponse string) *ChatCompletionsStreamResponse {
|
||||||
var choice ChatCompletionsStreamResponseChoice
|
var choice ChatCompletionsStreamResponseChoice
|
||||||
choice.Delta.Content = zhipuResponse
|
choice.Delta.Content = zhipuResponse
|
||||||
choice.FinishReason = ""
|
|
||||||
response := ChatCompletionsStreamResponse{
|
response := ChatCompletionsStreamResponse{
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
Created: common.GetTimestamp(),
|
Created: common.GetTimestamp(),
|
||||||
@ -176,7 +175,7 @@ func streamResponseZhipu2OpenAI(zhipuResponse string) *ChatCompletionsStreamResp
|
|||||||
func streamMetaResponseZhipu2OpenAI(zhipuResponse *ZhipuStreamMetaResponse) (*ChatCompletionsStreamResponse, *Usage) {
|
func streamMetaResponseZhipu2OpenAI(zhipuResponse *ZhipuStreamMetaResponse) (*ChatCompletionsStreamResponse, *Usage) {
|
||||||
var choice ChatCompletionsStreamResponseChoice
|
var choice ChatCompletionsStreamResponseChoice
|
||||||
choice.Delta.Content = ""
|
choice.Delta.Content = ""
|
||||||
choice.FinishReason = "stop"
|
choice.FinishReason = &stopFinishReason
|
||||||
response := ChatCompletionsStreamResponse{
|
response := ChatCompletionsStreamResponse{
|
||||||
Id: zhipuResponse.RequestId,
|
Id: zhipuResponse.RequestId,
|
||||||
Object: "chat.completion.chunk",
|
Object: "chat.completion.chunk",
|
||||||
|
@ -124,7 +124,7 @@ type ChatCompletionsStreamResponseChoice struct {
|
|||||||
Delta struct {
|
Delta struct {
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
} `json:"delta"`
|
} `json:"delta"`
|
||||||
FinishReason string `json:"finish_reason,omitempty"`
|
FinishReason *string `json:"finish_reason"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatCompletionsStreamResponse struct {
|
type ChatCompletionsStreamResponse struct {
|
||||||
|
@ -109,10 +109,10 @@ func AddToken(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(token.Name) == 0 || len(token.Name) > 20 {
|
if len(token.Name) == 0 || len(token.Name) > 30 {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": false,
|
"success": false,
|
||||||
"message": "令牌名称长度必须在1-20之间",
|
"message": "令牌名称过长",
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -171,6 +171,13 @@ func UpdateToken(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if len(token.Name) == 0 || len(token.Name) > 30 {
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"success": false,
|
||||||
|
"message": "令牌名称过长",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
cleanToken, err := model.GetTokenByIds(token.Id, userId)
|
cleanToken, err := model.GetTokenByIds(token.Id, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"一次兑换码批量生成的个数不能大于 100": "The number of redemption codes generated in a batch cannot be greater than 100",
|
"一次兑换码批量生成的个数不能大于 100": "The number of redemption codes generated in a batch cannot be greater than 100",
|
||||||
"通过令牌「%s」使用模型 %s 消耗 %s(模型倍率 %.2f,分组倍率 %.2f)": "Using model %s with token %s consumes %s (model rate %.2f, group rate %.2f)",
|
"通过令牌「%s」使用模型 %s 消耗 %s(模型倍率 %.2f,分组倍率 %.2f)": "Using model %s with token %s consumes %s (model rate %.2f, group rate %.2f)",
|
||||||
"当前分组上游负载已饱和,请稍后再试": "The current group load is saturated, please try again later",
|
"当前分组上游负载已饱和,请稍后再试": "The current group load is saturated, please try again later",
|
||||||
"令牌名称长度必须在1-20之间": "The length of the token name must be between 1-20",
|
"令牌名称过长": "Token name is too long",
|
||||||
"令牌已过期,无法启用,请先修改令牌过期时间,或者设置为永不过期": "The token has expired and cannot be enabled. Please modify the expiration time of the token, or set it to never expire.",
|
"令牌已过期,无法启用,请先修改令牌过期时间,或者设置为永不过期": "The token has expired and cannot be enabled. Please modify the expiration time of the token, or set it to never expire.",
|
||||||
"令牌可用额度已用尽,无法启用,请先修改令牌剩余额度,或者设置为无限额度": "The available quota of the token has been used up and cannot be enabled. Please modify the remaining quota of the token, or set it to unlimited quota",
|
"令牌可用额度已用尽,无法启用,请先修改令牌剩余额度,或者设置为无限额度": "The available quota of the token has been used up and cannot be enabled. Please modify the remaining quota of the token, or set it to unlimited quota",
|
||||||
"管理员关闭了密码登录": "The administrator has turned off password login",
|
"管理员关闭了密码登录": "The administrator has turned off password login",
|
||||||
@ -229,7 +229,7 @@
|
|||||||
"已是最新版本": "Is the latest version",
|
"已是最新版本": "Is the latest version",
|
||||||
"检查更新": "Check for updates",
|
"检查更新": "Check for updates",
|
||||||
"公告": "Announcement",
|
"公告": "Announcement",
|
||||||
"在此输入新的公告内容": "Enter new announcement content here",
|
"在此输入新的公告内容,支持 Markdown & HTML 代码": "Enter the new announcement content here, supports Markdown & HTML code",
|
||||||
"保存公告": "Save Announcement",
|
"保存公告": "Save Announcement",
|
||||||
"个性化设置": "Personalization Settings",
|
"个性化设置": "Personalization Settings",
|
||||||
"系统名称": "System Name",
|
"系统名称": "System Name",
|
||||||
@ -518,5 +518,6 @@
|
|||||||
",图片演示。": "related image demo.",
|
",图片演示。": "related image demo.",
|
||||||
"令牌创建成功,请在列表页面点击复制获取令牌!": "Token created successfully, please click copy on the list page to get the token!",
|
"令牌创建成功,请在列表页面点击复制获取令牌!": "Token created successfully, please click copy on the list page to get the token!",
|
||||||
"代理": "Proxy",
|
"代理": "Proxy",
|
||||||
"此项可选,用于通过代理站来进行 API 调用,请输入代理站地址,格式为:https://domain.com": "This is optional, used to make API calls through the proxy site, please enter the proxy site address, the format is: https://domain.com"
|
"此项可选,用于通过代理站来进行 API 调用,请输入代理站地址,格式为:https://domain.com": "This is optional, used to make API calls through the proxy site, please enter the proxy site address, the format is: https://domain.com",
|
||||||
|
"取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?": "Canceling password login will cause all users (including administrators) who have not bound other login methods to be unable to log in via password, confirm cancel?"
|
||||||
}
|
}
|
||||||
|
@ -447,8 +447,8 @@ const ChannelsTable = () => {
|
|||||||
<Button size='small' loading={loading} onClick={testAllChannels}>
|
<Button size='small' loading={loading} onClick={testAllChannels}>
|
||||||
测试所有已启用通道
|
测试所有已启用通道
|
||||||
</Button>
|
</Button>
|
||||||
<Button size='small' onClick={updateAllChannelsBalance}
|
{/* <Button size='small' onClick={updateAllChannelsBalance}
|
||||||
loading={loading || updatingBalance}>更新所有已启用通道余额</Button>
|
loading={loading || updatingBalance}>更新所有已启用通道余额</Button> */}
|
||||||
<Pagination
|
<Pagination
|
||||||
floated='right'
|
floated='right'
|
||||||
activePage={activePage}
|
activePage={activePage}
|
||||||
|
@ -112,7 +112,7 @@ const OtherSetting = () => {
|
|||||||
<Form.Group widths='equal'>
|
<Form.Group widths='equal'>
|
||||||
<Form.TextArea
|
<Form.TextArea
|
||||||
label='公告'
|
label='公告'
|
||||||
placeholder='在此输入新的公告内容'
|
placeholder='在此输入新的公告内容,支持 Markdown & HTML 代码'
|
||||||
value={inputs.Notice}
|
value={inputs.Notice}
|
||||||
name='Notice'
|
name='Notice'
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button, Form, Label, Message, Pagination, Table } from 'semantic-ui-react';
|
import { Button, Form, Label, Popup, Pagination, Table } from 'semantic-ui-react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { API, copy, showError, showInfo, showSuccess, showWarning, timestamp2string } from '../helpers';
|
import { API, copy, showError, showInfo, showSuccess, showWarning, timestamp2string } from '../helpers';
|
||||||
|
|
||||||
@ -240,15 +240,25 @@ const RedemptionsTable = () => {
|
|||||||
>
|
>
|
||||||
复制
|
复制
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Popup
|
||||||
size={'small'}
|
trigger={
|
||||||
negative
|
<Button size='small' negative>
|
||||||
onClick={() => {
|
删除
|
||||||
manageRedemption(redemption.id, 'delete', idx);
|
</Button>
|
||||||
}}
|
}
|
||||||
|
on='click'
|
||||||
|
flowing
|
||||||
|
hoverable
|
||||||
>
|
>
|
||||||
删除
|
<Button
|
||||||
</Button>
|
negative
|
||||||
|
onClick={() => {
|
||||||
|
manageRedemption(redemption.id, 'delete', idx);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
确认删除
|
||||||
|
</Button>
|
||||||
|
</Popup>
|
||||||
<Button
|
<Button
|
||||||
size={'small'}
|
size={'small'}
|
||||||
disabled={redemption.status === 3} // used
|
disabled={redemption.status === 3} // used
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button, Divider, Form, Grid, Header, Input, Message } from 'semantic-ui-react';
|
import { Button, Divider, Form, Grid, Header, Modal, Message } from 'semantic-ui-react';
|
||||||
import { API, removeTrailingSlash, showError } from '../helpers';
|
import { API, removeTrailingSlash, showError } from '../helpers';
|
||||||
|
|
||||||
const SystemSetting = () => {
|
const SystemSetting = () => {
|
||||||
@ -33,6 +33,7 @@ const SystemSetting = () => {
|
|||||||
let [loading, setLoading] = useState(false);
|
let [loading, setLoading] = useState(false);
|
||||||
const [EmailDomainWhitelist, setEmailDomainWhitelist] = useState([]);
|
const [EmailDomainWhitelist, setEmailDomainWhitelist] = useState([]);
|
||||||
const [restrictedDomainInput, setRestrictedDomainInput] = useState('');
|
const [restrictedDomainInput, setRestrictedDomainInput] = useState('');
|
||||||
|
const [showPasswordWarningModal, setShowPasswordWarningModal] = useState(false);
|
||||||
|
|
||||||
const getOptions = async () => {
|
const getOptions = async () => {
|
||||||
const res = await API.get('/api/option/');
|
const res = await API.get('/api/option/');
|
||||||
@ -95,6 +96,11 @@ const SystemSetting = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleInputChange = async (e, { name, value }) => {
|
const handleInputChange = async (e, { name, value }) => {
|
||||||
|
if (name === 'PasswordLoginEnabled' && inputs[name] === 'true') {
|
||||||
|
// block disabling password login
|
||||||
|
setShowPasswordWarningModal(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
name === 'Notice' ||
|
name === 'Notice' ||
|
||||||
name.startsWith('SMTP') ||
|
name.startsWith('SMTP') ||
|
||||||
@ -243,6 +249,32 @@ const SystemSetting = () => {
|
|||||||
name='PasswordLoginEnabled'
|
name='PasswordLoginEnabled'
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
|
{
|
||||||
|
showPasswordWarningModal &&
|
||||||
|
<Modal
|
||||||
|
open={showPasswordWarningModal}
|
||||||
|
onClose={() => setShowPasswordWarningModal(false)}
|
||||||
|
size={'tiny'}
|
||||||
|
style={{ maxWidth: '450px' }}
|
||||||
|
>
|
||||||
|
<Modal.Header>警告</Modal.Header>
|
||||||
|
<Modal.Content>
|
||||||
|
<p>取消密码登录将导致所有未绑定其他登录方式的用户(包括管理员)无法通过密码登录,确认取消?</p>
|
||||||
|
</Modal.Content>
|
||||||
|
<Modal.Actions>
|
||||||
|
<Button onClick={() => setShowPasswordWarningModal(false)}>取消</Button>
|
||||||
|
<Button
|
||||||
|
color='yellow'
|
||||||
|
onClick={async () => {
|
||||||
|
setShowPasswordWarningModal(false);
|
||||||
|
await updateOption('PasswordLoginEnabled', 'false');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
</Modal.Actions>
|
||||||
|
</Modal>
|
||||||
|
}
|
||||||
<Form.Checkbox
|
<Form.Checkbox
|
||||||
checked={inputs.PasswordRegisterEnabled === 'true'}
|
checked={inputs.PasswordRegisterEnabled === 'true'}
|
||||||
label='允许通过密码进行注册'
|
label='允许通过密码进行注册'
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { toastConstants } from '../constants';
|
import { toastConstants } from '../constants';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const HTMLToastContent = ({ htmlContent }) => {
|
||||||
|
return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
|
||||||
|
};
|
||||||
|
export default HTMLToastContent;
|
||||||
export function isAdmin() {
|
export function isAdmin() {
|
||||||
let user = localStorage.getItem('user');
|
let user = localStorage.getItem('user');
|
||||||
if (!user) return false;
|
if (!user) return false;
|
||||||
@ -107,8 +112,12 @@ export function showInfo(message) {
|
|||||||
toast.info(message, showInfoOptions);
|
toast.info(message, showInfoOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showNotice(message) {
|
export function showNotice(message, isHTML = false) {
|
||||||
toast.info(message, showNoticeOptions);
|
if (isHTML) {
|
||||||
|
toast(<HTMLToastContent htmlContent={message} />, showNoticeOptions);
|
||||||
|
} else {
|
||||||
|
toast.info(message, showNoticeOptions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openPage(url) {
|
export function openPage(url) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button, Form, Header, Input, Message, Segment } from 'semantic-ui-react';
|
import { Button, Form, Header, Input, Message, Segment } from 'semantic-ui-react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { API, showError, showInfo, showSuccess, verifyJSON } from '../../helpers';
|
import { API, showError, showInfo, showSuccess, verifyJSON } from '../../helpers';
|
||||||
import { CHANNEL_OPTIONS } from '../../constants';
|
import { CHANNEL_OPTIONS } from '../../constants';
|
||||||
|
|
||||||
@ -12,9 +12,14 @@ const MODEL_MAPPING_EXAMPLE = {
|
|||||||
|
|
||||||
const EditChannel = () => {
|
const EditChannel = () => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
const channelId = params.id;
|
const channelId = params.id;
|
||||||
const isEdit = channelId !== undefined;
|
const isEdit = channelId !== undefined;
|
||||||
const [loading, setLoading] = useState(isEdit);
|
const [loading, setLoading] = useState(isEdit);
|
||||||
|
const handleCancel = () => {
|
||||||
|
navigate('/channel');
|
||||||
|
};
|
||||||
|
|
||||||
const originInputs = {
|
const originInputs = {
|
||||||
name: '',
|
name: '',
|
||||||
type: 1,
|
type: 1,
|
||||||
@ -381,6 +386,7 @@ const EditChannel = () => {
|
|||||||
</Form.Field>
|
</Form.Field>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
<Button onClick={handleCancel}>取消</Button>
|
||||||
<Button type={isEdit ? 'button' : 'submit'} positive onClick={submit}>提交</Button>
|
<Button type={isEdit ? 'button' : 'submit'} positive onClick={submit}>提交</Button>
|
||||||
</Form>
|
</Form>
|
||||||
</Segment>
|
</Segment>
|
||||||
|
@ -14,10 +14,11 @@ const Home = () => {
|
|||||||
const { success, message, data } = res.data;
|
const { success, message, data } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
let oldNotice = localStorage.getItem('notice');
|
let oldNotice = localStorage.getItem('notice');
|
||||||
if (data !== oldNotice && data !== '') {
|
if (data !== oldNotice && data !== '') {
|
||||||
showNotice(data);
|
const htmlNotice = marked(data);
|
||||||
localStorage.setItem('notice', data);
|
showNotice(htmlNotice, true);
|
||||||
}
|
localStorage.setItem('notice', data);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
showError(message);
|
showError(message);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button, Form, Header, Segment } from 'semantic-ui-react';
|
import { Button, Form, Header, Segment } from 'semantic-ui-react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { API, downloadTextAsFile, showError, showSuccess } from '../../helpers';
|
import { API, downloadTextAsFile, showError, showSuccess } from '../../helpers';
|
||||||
import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
|
import { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
|
||||||
|
|
||||||
const EditRedemption = () => {
|
const EditRedemption = () => {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
const redemptionId = params.id;
|
const redemptionId = params.id;
|
||||||
const isEdit = redemptionId !== undefined;
|
const isEdit = redemptionId !== undefined;
|
||||||
const [loading, setLoading] = useState(isEdit);
|
const [loading, setLoading] = useState(isEdit);
|
||||||
@ -17,6 +18,10 @@ const EditRedemption = () => {
|
|||||||
const [inputs, setInputs] = useState(originInputs);
|
const [inputs, setInputs] = useState(originInputs);
|
||||||
const { name, quota, count } = inputs;
|
const { name, quota, count } = inputs;
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
navigate('/redemption');
|
||||||
|
};
|
||||||
|
|
||||||
const handleInputChange = (e, { name, value }) => {
|
const handleInputChange = (e, { name, value }) => {
|
||||||
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
setInputs((inputs) => ({ ...inputs, [name]: value }));
|
||||||
};
|
};
|
||||||
@ -113,6 +118,7 @@ const EditRedemption = () => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
<Button positive onClick={submit}>提交</Button>
|
<Button positive onClick={submit}>提交</Button>
|
||||||
|
<Button onClick={handleCancel}>取消</Button>
|
||||||
</Form>
|
</Form>
|
||||||
</Segment>
|
</Segment>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user