mirror of
				https://github.com/linux-do/new-api.git
				synced 2025-11-04 13:23:42 +08:00 
			
		
		
		
	chore: resolve conflicts
This commit is contained in:
		@@ -121,7 +121,10 @@ func responseAli2OpenAI(response *AliChatResponse) *OpenAITextResponse {
 | 
			
		||||
func streamResponseAli2OpenAI(aliResponse *AliChatResponse) *ChatCompletionsStreamResponse {
 | 
			
		||||
	var choice ChatCompletionsStreamResponseChoice
 | 
			
		||||
	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{
 | 
			
		||||
		Id:      aliResponse.RequestId,
 | 
			
		||||
		Object:  "chat.completion.chunk",
 | 
			
		||||
 
 | 
			
		||||
@@ -120,7 +120,9 @@ func responseBaidu2OpenAI(response *BaiduChatResponse) *OpenAITextResponse {
 | 
			
		||||
func streamResponseBaidu2OpenAI(baiduResponse *BaiduChatStreamResponse) *ChatCompletionsStreamResponse {
 | 
			
		||||
	var choice ChatCompletionsStreamResponseChoice
 | 
			
		||||
	choice.Delta.Content = baiduResponse.Result
 | 
			
		||||
	choice.FinishReason = "stop"
 | 
			
		||||
	if baiduResponse.IsEnd {
 | 
			
		||||
		choice.FinishReason = &stopFinishReason
 | 
			
		||||
	}
 | 
			
		||||
	response := ChatCompletionsStreamResponse{
 | 
			
		||||
		Id:      baiduResponse.Id,
 | 
			
		||||
		Object:  "chat.completion.chunk",
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,10 @@ func requestOpenAI2Claude(textRequest GeneralOpenAIRequest) *ClaudeRequest {
 | 
			
		||||
func streamResponseClaude2OpenAI(claudeResponse *ClaudeResponse) *ChatCompletionsStreamResponse {
 | 
			
		||||
	var choice ChatCompletionsStreamResponseChoice
 | 
			
		||||
	choice.Delta.Content = claudeResponse.Completion
 | 
			
		||||
	choice.FinishReason = stopReasonClaude2OpenAI(claudeResponse.StopReason)
 | 
			
		||||
	finishReason := stopReasonClaude2OpenAI(claudeResponse.StopReason)
 | 
			
		||||
	if finishReason != "null" {
 | 
			
		||||
		choice.FinishReason = &finishReason
 | 
			
		||||
	}
 | 
			
		||||
	var response ChatCompletionsStreamResponse
 | 
			
		||||
	response.Object = "chat.completion.chunk"
 | 
			
		||||
	response.Model = claudeResponse.Model
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ func streamResponsePaLM2OpenAI(palmResponse *PaLMChatResponse) *ChatCompletionsS
 | 
			
		||||
	if len(palmResponse.Candidates) > 0 {
 | 
			
		||||
		choice.Delta.Content = palmResponse.Candidates[0].Content
 | 
			
		||||
	}
 | 
			
		||||
	choice.FinishReason = "stop"
 | 
			
		||||
	choice.FinishReason = &stopFinishReason
 | 
			
		||||
	var response ChatCompletionsStreamResponse
 | 
			
		||||
	response.Object = "chat.completion.chunk"
 | 
			
		||||
	response.Model = "palm2"
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,8 @@ import (
 | 
			
		||||
	"one-api/common"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var stopFinishReason = "stop"
 | 
			
		||||
 | 
			
		||||
var tokenEncoderMap = map[string]*tiktoken.Tiktoken{}
 | 
			
		||||
 | 
			
		||||
func getTokenEncoder(model string) *tiktoken.Tiktoken {
 | 
			
		||||
 
 | 
			
		||||
@@ -138,6 +138,9 @@ func streamResponseXunfei2OpenAI(xunfeiResponse *XunfeiChatResponse) *ChatComple
 | 
			
		||||
	}
 | 
			
		||||
	var choice ChatCompletionsStreamResponseChoice
 | 
			
		||||
	choice.Delta.Content = xunfeiResponse.Payload.Choices.Text[0].Content
 | 
			
		||||
	if xunfeiResponse.Payload.Choices.Status == 2 {
 | 
			
		||||
		choice.FinishReason = &stopFinishReason
 | 
			
		||||
	}
 | 
			
		||||
	response := ChatCompletionsStreamResponse{
 | 
			
		||||
		Object:  "chat.completion.chunk",
 | 
			
		||||
		Created: common.GetTimestamp(),
 | 
			
		||||
 
 | 
			
		||||
@@ -163,7 +163,6 @@ func responseZhipu2OpenAI(response *ZhipuResponse) *OpenAITextResponse {
 | 
			
		||||
func streamResponseZhipu2OpenAI(zhipuResponse string) *ChatCompletionsStreamResponse {
 | 
			
		||||
	var choice ChatCompletionsStreamResponseChoice
 | 
			
		||||
	choice.Delta.Content = zhipuResponse
 | 
			
		||||
	choice.FinishReason = ""
 | 
			
		||||
	response := ChatCompletionsStreamResponse{
 | 
			
		||||
		Object:  "chat.completion.chunk",
 | 
			
		||||
		Created: common.GetTimestamp(),
 | 
			
		||||
@@ -176,7 +175,7 @@ func streamResponseZhipu2OpenAI(zhipuResponse string) *ChatCompletionsStreamResp
 | 
			
		||||
func streamMetaResponseZhipu2OpenAI(zhipuResponse *ZhipuStreamMetaResponse) (*ChatCompletionsStreamResponse, *Usage) {
 | 
			
		||||
	var choice ChatCompletionsStreamResponseChoice
 | 
			
		||||
	choice.Delta.Content = ""
 | 
			
		||||
	choice.FinishReason = "stop"
 | 
			
		||||
	choice.FinishReason = &stopFinishReason
 | 
			
		||||
	response := ChatCompletionsStreamResponse{
 | 
			
		||||
		Id:      zhipuResponse.RequestId,
 | 
			
		||||
		Object:  "chat.completion.chunk",
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,7 @@ type ChatCompletionsStreamResponseChoice struct {
 | 
			
		||||
	Delta struct {
 | 
			
		||||
		Content string `json:"content"`
 | 
			
		||||
	} `json:"delta"`
 | 
			
		||||
	FinishReason string `json:"finish_reason,omitempty"`
 | 
			
		||||
	FinishReason *string `json:"finish_reason"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ChatCompletionsStreamResponse struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -109,10 +109,10 @@ func AddToken(c *gin.Context) {
 | 
			
		||||
		})
 | 
			
		||||
		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{
 | 
			
		||||
			"success": false,
 | 
			
		||||
			"message": "令牌名称长度必须在1-20之间",
 | 
			
		||||
			"message": "令牌名称过长",
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
@@ -171,6 +171,13 @@ func UpdateToken(c *gin.Context) {
 | 
			
		||||
		})
 | 
			
		||||
		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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		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",
 | 
			
		||||
  "通过令牌「%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",
 | 
			
		||||
  "令牌名称长度必须在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 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",
 | 
			
		||||
@@ -229,7 +229,7 @@
 | 
			
		||||
  "已是最新版本": "Is the latest version",
 | 
			
		||||
  "检查更新": "Check for updates",
 | 
			
		||||
  "公告": "Announcement",
 | 
			
		||||
  "在此输入新的公告内容": "Enter new announcement content here",
 | 
			
		||||
  "在此输入新的公告内容,支持 Markdown & HTML 代码": "Enter the new announcement content here, supports Markdown & HTML code",
 | 
			
		||||
  "保存公告": "Save Announcement",
 | 
			
		||||
  "个性化设置": "Personalization Settings",
 | 
			
		||||
  "系统名称": "System Name",
 | 
			
		||||
@@ -518,5 +518,6 @@
 | 
			
		||||
  ",图片演示。": "related image demo.",
 | 
			
		||||
  "令牌创建成功,请在列表页面点击复制获取令牌!": "Token created successfully, please click copy on the list page to get the token!",
 | 
			
		||||
  "代理": "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>
 | 
			
		||||
              <Button size='small' onClick={updateAllChannelsBalance}
 | 
			
		||||
                      loading={loading || updatingBalance}>更新所有已启用通道余额</Button>
 | 
			
		||||
              {/* <Button size='small' onClick={updateAllChannelsBalance}
 | 
			
		||||
                      loading={loading || updatingBalance}>更新所有已启用通道余额</Button> */}
 | 
			
		||||
              <Pagination
 | 
			
		||||
                floated='right'
 | 
			
		||||
                activePage={activePage}
 | 
			
		||||
 
 | 
			
		||||
@@ -112,7 +112,7 @@ const OtherSetting = () => {
 | 
			
		||||
          <Form.Group widths='equal'>
 | 
			
		||||
            <Form.TextArea
 | 
			
		||||
              label='公告'
 | 
			
		||||
              placeholder='在此输入新的公告内容'
 | 
			
		||||
              placeholder='在此输入新的公告内容,支持 Markdown & HTML 代码'
 | 
			
		||||
              value={inputs.Notice}
 | 
			
		||||
              name='Notice'
 | 
			
		||||
              onChange={handleInputChange}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
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 { API, copy, showError, showInfo, showSuccess, showWarning, timestamp2string } from '../helpers';
 | 
			
		||||
 | 
			
		||||
@@ -240,15 +240,25 @@ const RedemptionsTable = () => {
 | 
			
		||||
                      >
 | 
			
		||||
                        复制
 | 
			
		||||
                      </Button>
 | 
			
		||||
                      <Button
 | 
			
		||||
                        size={'small'}
 | 
			
		||||
                        negative
 | 
			
		||||
                        onClick={() => {
 | 
			
		||||
                          manageRedemption(redemption.id, 'delete', idx);
 | 
			
		||||
                        }}
 | 
			
		||||
                      <Popup
 | 
			
		||||
                        trigger={
 | 
			
		||||
                          <Button size='small' negative>
 | 
			
		||||
                            删除
 | 
			
		||||
                          </Button>
 | 
			
		||||
                        }
 | 
			
		||||
                        on='click'
 | 
			
		||||
                        flowing
 | 
			
		||||
                        hoverable
 | 
			
		||||
                      >
 | 
			
		||||
                        删除
 | 
			
		||||
                      </Button>
 | 
			
		||||
                        <Button
 | 
			
		||||
                          negative
 | 
			
		||||
                          onClick={() => {
 | 
			
		||||
                            manageRedemption(redemption.id, 'delete', idx);
 | 
			
		||||
                          }}
 | 
			
		||||
                        >
 | 
			
		||||
                          确认删除
 | 
			
		||||
                        </Button>
 | 
			
		||||
                      </Popup>
 | 
			
		||||
                      <Button
 | 
			
		||||
                        size={'small'}
 | 
			
		||||
                        disabled={redemption.status === 3}  // used
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
const SystemSetting = () => {
 | 
			
		||||
@@ -33,6 +33,7 @@ const SystemSetting = () => {
 | 
			
		||||
  let [loading, setLoading] = useState(false);
 | 
			
		||||
  const [EmailDomainWhitelist, setEmailDomainWhitelist] = useState([]);
 | 
			
		||||
  const [restrictedDomainInput, setRestrictedDomainInput] = useState('');
 | 
			
		||||
  const [showPasswordWarningModal, setShowPasswordWarningModal] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const getOptions = async () => {
 | 
			
		||||
    const res = await API.get('/api/option/');
 | 
			
		||||
@@ -95,6 +96,11 @@ const SystemSetting = () => {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleInputChange = async (e, { name, value }) => {
 | 
			
		||||
    if (name === 'PasswordLoginEnabled' && inputs[name] === 'true') {
 | 
			
		||||
      // block disabling password login
 | 
			
		||||
      setShowPasswordWarningModal(true);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (
 | 
			
		||||
      name === 'Notice' ||
 | 
			
		||||
      name.startsWith('SMTP') ||
 | 
			
		||||
@@ -243,6 +249,32 @@ const SystemSetting = () => {
 | 
			
		||||
              name='PasswordLoginEnabled'
 | 
			
		||||
              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
 | 
			
		||||
              checked={inputs.PasswordRegisterEnabled === 'true'}
 | 
			
		||||
              label='允许通过密码进行注册'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,11 @@
 | 
			
		||||
import { toast } from 'react-toastify';
 | 
			
		||||
import { toastConstants } from '../constants';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
const HTMLToastContent = ({ htmlContent }) => {
 | 
			
		||||
  return <div dangerouslySetInnerHTML={{ __html: htmlContent }} />;
 | 
			
		||||
};
 | 
			
		||||
export default HTMLToastContent;
 | 
			
		||||
export function isAdmin() {
 | 
			
		||||
  let user = localStorage.getItem('user');
 | 
			
		||||
  if (!user) return false;
 | 
			
		||||
@@ -107,8 +112,12 @@ export function showInfo(message) {
 | 
			
		||||
  toast.info(message, showInfoOptions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function showNotice(message) {
 | 
			
		||||
  toast.info(message, showNoticeOptions);
 | 
			
		||||
export function showNotice(message, isHTML = false) {
 | 
			
		||||
  if (isHTML) {
 | 
			
		||||
    toast(<HTMLToastContent htmlContent={message} />, showNoticeOptions);
 | 
			
		||||
  } else {
 | 
			
		||||
    toast.info(message, showNoticeOptions);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function openPage(url) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import React, { useEffect, useState } from '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 { CHANNEL_OPTIONS } from '../../constants';
 | 
			
		||||
 | 
			
		||||
@@ -12,9 +12,14 @@ const MODEL_MAPPING_EXAMPLE = {
 | 
			
		||||
 | 
			
		||||
const EditChannel = () => {
 | 
			
		||||
  const params = useParams();
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
  const channelId = params.id;
 | 
			
		||||
  const isEdit = channelId !== undefined;
 | 
			
		||||
  const [loading, setLoading] = useState(isEdit);
 | 
			
		||||
  const handleCancel = () => {
 | 
			
		||||
    navigate('/channel');
 | 
			
		||||
  };
 | 
			
		||||
  
 | 
			
		||||
  const originInputs = {
 | 
			
		||||
    name: '',
 | 
			
		||||
    type: 1,
 | 
			
		||||
@@ -381,6 +386,7 @@ const EditChannel = () => {
 | 
			
		||||
              </Form.Field>
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
          <Button onClick={handleCancel}>取消</Button>
 | 
			
		||||
          <Button type={isEdit ? 'button' : 'submit'} positive onClick={submit}>提交</Button>
 | 
			
		||||
        </Form>
 | 
			
		||||
      </Segment>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,10 +14,11 @@ const Home = () => {
 | 
			
		||||
    const { success, message, data } = res.data;
 | 
			
		||||
    if (success) {
 | 
			
		||||
      let oldNotice = localStorage.getItem('notice');
 | 
			
		||||
      if (data !== oldNotice && data !== '') {
 | 
			
		||||
        showNotice(data);
 | 
			
		||||
        localStorage.setItem('notice', data);
 | 
			
		||||
      }
 | 
			
		||||
        if (data !== oldNotice && data !== '') {
 | 
			
		||||
            const htmlNotice = marked(data);
 | 
			
		||||
            showNotice(htmlNotice, true);
 | 
			
		||||
            localStorage.setItem('notice', data);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
      showError(message);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,12 @@
 | 
			
		||||
import React, { useEffect, useState } from '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 { renderQuota, renderQuotaWithPrompt } from '../../helpers/render';
 | 
			
		||||
 | 
			
		||||
const EditRedemption = () => {
 | 
			
		||||
  const params = useParams();
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
  const redemptionId = params.id;
 | 
			
		||||
  const isEdit = redemptionId !== undefined;
 | 
			
		||||
  const [loading, setLoading] = useState(isEdit);
 | 
			
		||||
@@ -17,6 +18,10 @@ const EditRedemption = () => {
 | 
			
		||||
  const [inputs, setInputs] = useState(originInputs);
 | 
			
		||||
  const { name, quota, count } = inputs;
 | 
			
		||||
 | 
			
		||||
  const handleCancel = () => {
 | 
			
		||||
    navigate('/redemption');
 | 
			
		||||
  };
 | 
			
		||||
  
 | 
			
		||||
  const handleInputChange = (e, { name, value }) => {
 | 
			
		||||
    setInputs((inputs) => ({ ...inputs, [name]: value }));
 | 
			
		||||
  };
 | 
			
		||||
@@ -113,6 +118,7 @@ const EditRedemption = () => {
 | 
			
		||||
            </>
 | 
			
		||||
          }
 | 
			
		||||
          <Button positive onClick={submit}>提交</Button>
 | 
			
		||||
          <Button onClick={handleCancel}>取消</Button>
 | 
			
		||||
        </Form>
 | 
			
		||||
      </Segment>
 | 
			
		||||
    </>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user